1790 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 22; RUN: opt < %s -passes=memcpyopt -verify-memoryssa -S | FileCheck %s3 4%struct.Foo = type { i32, i32, i32 }5 6declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg)7declare void @llvm.memcpy.p1.p0.i64(ptr addrspace(1) noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg)8declare void @llvm.memcpy.p2.p1.i64(ptr addrspace(2) noalias nocapture writeonly, ptr addrspace(1) noalias nocapture readonly, i64, i1 immarg)9declare void @llvm.memmove.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1 immarg)10declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg)11 12declare void @llvm.lifetime.start.p0(ptr nocapture)13declare void @llvm.lifetime.end.p0(ptr nocapture)14declare void @llvm.lifetime.start.p1(ptr addrspace(1) nocapture)15declare void @llvm.lifetime.end.p1(ptr addrspace(1) nocapture)16declare void @llvm.lifetime.start.p2(ptr addrspace(2) nocapture)17declare void @llvm.lifetime.end.p2(ptr addrspace(2) nocapture)18 19declare i32 @use_nocapture(ptr nocapture)20declare i32 @use_maycapture(ptr noundef)21declare i32 @use_readonly(ptr readonly)22declare i32 @use_writeonly(ptr noundef) memory(write)23 24define void @basic_memcpy() {25; CHECK-LABEL: define void @basic_memcpy() {26; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 427; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 428; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])29; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])30; CHECK-NEXT: ret void31;32 %src = alloca %struct.Foo, align 433 %dest = alloca %struct.Foo, align 434 call void @llvm.lifetime.start.p0(ptr nocapture %src)35 call void @llvm.lifetime.start.p0(ptr nocapture %dest)36 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src37 %1 = call i32 @use_nocapture(ptr nocapture %src)38 39 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)40 41 %2 = call i32 @use_nocapture(ptr nocapture %dest)42 43 call void @llvm.lifetime.end.p0(ptr nocapture %src)44 call void @llvm.lifetime.end.p0(ptr nocapture %dest)45 ret void46}47 48define i32 @use_not_dominated_by_src_alloca() {49; CHECK-LABEL: define i32 @use_not_dominated_by_src_alloca() {50; CHECK-NEXT: [[SRC:%.*]] = alloca i8, align 451; CHECK-NEXT: [[DEST_GEP:%.*]] = getelementptr i64, ptr [[SRC]], i64 -152; CHECK-NEXT: [[DEST_USE:%.*]] = load i8, ptr [[DEST_GEP]], align 153; CHECK-NEXT: ret i32 054;55 %dest = alloca i1, align 156 ; Replacing the use of dest with src causes no domination uses.57 %dest.gep = getelementptr i64, ptr %dest, i64 -158 %dest.use = load i8, ptr %dest.gep, align 159 %src = alloca i8, align 460 %src.val = load i1, ptr %src, align 461 62 store i1 %src.val, ptr %dest, align 163 64 ret i32 065}66 67define void @basic_memmove() {68; CHECK-LABEL: define void @basic_memmove() {69; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 470; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 471; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])72; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])73; CHECK-NEXT: ret void74;75 %src = alloca %struct.Foo, align 476 %dest = alloca %struct.Foo, align 477 call void @llvm.lifetime.start.p0(ptr nocapture %src)78 call void @llvm.lifetime.start.p0(ptr nocapture %dest)79 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src80 %1 = call i32 @use_nocapture(ptr nocapture %src)81 82 call void @llvm.memmove.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)83 84 %2 = call i32 @use_nocapture(ptr nocapture %dest)85 86 call void @llvm.lifetime.end.p0(ptr nocapture %src)87 call void @llvm.lifetime.end.p0(ptr nocapture %dest)88 ret void89}90 91; Tests that the optimization succeeds with a load/store pair.92define void @load_store() {93; CHECK-LABEL: define void @load_store() {94; CHECK-NEXT: [[SRC:%.*]] = alloca i32, align 495; CHECK-NEXT: store i32 42, ptr [[SRC]], align 496; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])97; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])98; CHECK-NEXT: ret void99;100 %src = alloca i32, align 4101 %dest = alloca i32, align 4102 call void @llvm.lifetime.start.p0(ptr nocapture %src)103 call void @llvm.lifetime.start.p0(ptr nocapture %dest)104 store i32 42, ptr %src105 %1 = call i32 @use_nocapture(ptr nocapture %src)106 107 %src.val = load i32, ptr %src108 store i32 %src.val, ptr %dest109 110 %2 = call i32 @use_nocapture(ptr nocapture %dest)111 call void @llvm.lifetime.end.p0(ptr nocapture %src)112 call void @llvm.lifetime.end.p0(ptr nocapture %dest)113 ret void114}115 116; Test scalable vectors.117define void @load_store_scalable(<vscale x 4 x i32> %x) {118; CHECK-LABEL: define void @load_store_scalable119; CHECK-SAME: (<vscale x 4 x i32> [[X:%.*]]) {120; CHECK-NEXT: [[SRC:%.*]] = alloca <vscale x 4 x i32>, align 16121; CHECK-NEXT: store <vscale x 4 x i32> [[X]], ptr [[SRC]], align 16122; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])123; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])124; CHECK-NEXT: ret void125;126 %src = alloca <vscale x 4 x i32>127 %dest = alloca <vscale x 4 x i32>128 call void @llvm.lifetime.start.p0(ptr nocapture %src)129 call void @llvm.lifetime.start.p0(ptr nocapture %dest)130 store <vscale x 4 x i32> %x, ptr %src131 %1 = call i32 @use_nocapture(ptr nocapture %src)132 133 %src.val = load <vscale x 4 x i32>, ptr %src134 store <vscale x 4 x i32> %src.val, ptr %dest135 136 %2 = call i32 @use_nocapture(ptr nocapture %dest)137 138 call void @llvm.lifetime.end.p0(ptr nocapture %src)139 call void @llvm.lifetime.end.p0(ptr nocapture %dest)140 ret void141}142 143; Tests that merging two allocas shouldn't be more poisonous, smaller aligned src is valid.144define void @align_up() {145; CHECK-LABEL: define void @align_up() {146; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 8147; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4148; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])149; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])150; CHECK-NEXT: ret void151;152 %src = alloca %struct.Foo, align 4153 %dest = alloca %struct.Foo, align 8154 call void @llvm.lifetime.start.p0(ptr nocapture %src)155 call void @llvm.lifetime.start.p0(ptr nocapture %dest)156 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src157 %1 = call i32 @use_nocapture(ptr nocapture %src)158 159 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)160 161 %2 = call i32 @use_nocapture(ptr nocapture %dest)162 call void @llvm.lifetime.end.p0(ptr nocapture %src)163 call void @llvm.lifetime.end.p0(ptr nocapture %dest)164 ret void165}166 167; Tests that we correctly remove extra lifetime intrinsics when performing the168; optimization.169define void @remove_extra_lifetime_intrinsics() {170; CHECK-LABEL: define void @remove_extra_lifetime_intrinsics() {171; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4172; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4173; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])174; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])175; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])176; CHECK-NEXT: ret void177;178 %src = alloca %struct.Foo, align 4179 %dest = alloca %struct.Foo, align 4180 call void @llvm.lifetime.start.p0(ptr nocapture %src)181 call void @llvm.lifetime.start.p0(ptr nocapture %dest)182 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src183 %1 = call i32 @use_nocapture(ptr nocapture %src)184 185 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)186 187 call void @llvm.lifetime.end.p0(ptr nocapture %src)188 %2 = call i32 @use_nocapture(ptr nocapture %dest)189 call void @llvm.lifetime.end.p0(ptr nocapture %src)190 call void @llvm.lifetime.start.p0(ptr nocapture %src)191 %3 = call i32 @use_nocapture(ptr nocapture %dest)192 call void @llvm.lifetime.end.p0(ptr nocapture %src)193 call void @llvm.lifetime.start.p0(ptr nocapture %dest)194 call void @llvm.lifetime.end.p0(ptr nocapture %dest)195 ret void196}197 198; Tests that we won't insert lifetime markers if they don't exist originally.199define void @no_lifetime() {200; CHECK-LABEL: define void @no_lifetime() {201; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4202; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4203; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])204; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])205; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])206; CHECK-NEXT: ret void207;208 %src = alloca %struct.Foo, align 4209 %dest = alloca %struct.Foo, align 4210 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src211 %1 = call i32 @use_nocapture(ptr nocapture %src)212 213 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)214 215 %2 = call i32 @use_nocapture(ptr nocapture %dest)216 %3 = call i32 @use_nocapture(ptr nocapture %dest)217 ret void218}219 220; Tests that aliasing src or dest but no modification desn't prevent transformations.221define void @alias_no_mod() {222; CHECK-LABEL: define void @alias_no_mod() {223; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4224; CHECK-NEXT: [[DEST_ALIAS:%.*]] = getelementptr [[STRUCT_FOO]], ptr [[SRC]], i32 0, i32 0225; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4226; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])227; CHECK-NEXT: [[SRC_ALIAS:%.*]] = getelementptr [[STRUCT_FOO]], ptr [[SRC]], i32 0, i32 0228; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])229; CHECK-NEXT: ret void230;231 %src = alloca %struct.Foo, align 4232 %dest = alloca %struct.Foo, align 4233 call void @llvm.lifetime.start.p0(ptr nocapture %src)234 call void @llvm.lifetime.start.p0(ptr nocapture %dest)235 %dest.alias = getelementptr %struct.Foo, ptr %dest, i32 0, i32 0236 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src237 %1 = call i32 @use_nocapture(ptr nocapture %src)238 239 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)240 241 %src.alias = getelementptr %struct.Foo, ptr %src, i32 0, i32 0242 %2 = call i32 @use_nocapture(ptr nocapture %dest)243 call void @llvm.lifetime.end.p0(ptr nocapture %src)244 call void @llvm.lifetime.end.p0(ptr nocapture %dest)245 ret void246}247 248; Scope domain249!0 = !{!0}250; Scope in that domain251!1 = !{!1, !0}252; Scope list253!2 = !{!1}254 255!3 = !{!"Whatever"}256 257; Tests that we remove scoped noalias metadata from a call.258define void @remove_scoped_noalias() {259; CHECK-LABEL: define void @remove_scoped_noalias() {260; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4261; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4262; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])263; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])264; CHECK-NEXT: ret void265;266 %src = alloca %struct.Foo, align 4267 %dest = alloca %struct.Foo, align 4268 call void @llvm.lifetime.start.p0(ptr nocapture %src)269 call void @llvm.lifetime.start.p0(ptr nocapture %dest)270 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src271 %1 = call i32 @use_nocapture(ptr nocapture %src), !alias.scope !2272 273 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)274 275 call void @llvm.lifetime.end.p0(ptr nocapture %src)276 %2 = call i32 @use_nocapture(ptr nocapture %dest), !noalias !2277 call void @llvm.lifetime.end.p0(ptr nocapture %dest)278 ret void279}280 281; Tests that we remove metadata on the merged alloca.282define void @remove_alloca_metadata() {283; CHECK-LABEL: define void @remove_alloca_metadata() {284; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4285; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4286; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])287; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])288; CHECK-NEXT: ret void289;290 %src = alloca %struct.Foo, align 4, !annotation !3291 %dest = alloca %struct.Foo, align 4292 call void @llvm.lifetime.start.p0(ptr nocapture %src)293 call void @llvm.lifetime.start.p0(ptr nocapture %dest)294 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src295 %1 = call i32 @use_nocapture(ptr nocapture %src), !alias.scope !2296 297 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)298 299 %2 = call i32 @use_nocapture(ptr nocapture %dest), !noalias !2300 call void @llvm.lifetime.end.p0(ptr nocapture %src)301 call void @llvm.lifetime.end.p0(ptr nocapture %dest)302 ret void303}304 305; Tests that we remove scoped noalias metadata from a call.306; And confirm that don't crash on noalias metadata on lifetime markers.307define void @noalias_on_lifetime() {308; CHECK-LABEL: define void @noalias_on_lifetime() {309; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4310; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4311; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])312; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])313; CHECK-NEXT: ret void314;315 %src = alloca %struct.Foo, align 4316 %dest = alloca %struct.Foo, align 4317 call void @llvm.lifetime.start.p0(ptr nocapture %src)318 call void @llvm.lifetime.start.p0(ptr nocapture %dest)319 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src320 %1 = call i32 @use_nocapture(ptr nocapture %src), !alias.scope !2321 322 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)323 324 call void @llvm.lifetime.end.p0(ptr nocapture %src), !alias.scope !2325 %2 = call i32 @use_nocapture(ptr nocapture %dest), !noalias !2326 call void @llvm.lifetime.end.p0(ptr nocapture %dest), !noalias !2327 ret void328}329 330; Tests that we can merge alloca if the dest and src has only refs except lifetime intrinsics.331define void @src_ref_dest_ref_after_copy() {332; CHECK-LABEL: define void @src_ref_dest_ref_after_copy() {333; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4334; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4335; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_readonly(ptr captures(none) [[SRC]])336; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_readonly(ptr captures(none) [[SRC]])337; CHECK-NEXT: ret void338;339 %src = alloca %struct.Foo, align 4340 %dest = alloca %struct.Foo, align 4341 call void @llvm.lifetime.start.p0(ptr nocapture %src)342 call void @llvm.lifetime.start.p0(ptr nocapture %dest)343 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src344 345 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)346 347 %1 = call i32 @use_readonly(ptr nocapture %src)348 %2 = call i32 @use_readonly(ptr nocapture %dest)349 call void @llvm.lifetime.end.p0(ptr nocapture %src)350 call void @llvm.lifetime.end.p0(ptr nocapture %dest)351 ret void352}353 354; Tests that we can merge alloca if the dest and src has only mods.355define void @src_mod_dest_mod_after_copy() {356; CHECK-LABEL: define void @src_mod_dest_mod_after_copy() {357; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4358; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4359; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_writeonly(ptr captures(none) [[SRC]])360; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_writeonly(ptr captures(none) [[SRC]])361; CHECK-NEXT: ret void362;363 %src = alloca %struct.Foo, align 4364 %dest = alloca %struct.Foo, align 4365 call void @llvm.lifetime.start.p0(ptr nocapture %src)366 call void @llvm.lifetime.start.p0(ptr nocapture %dest)367 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src368 369 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)370 371 %1 = call i32 @use_writeonly(ptr nocapture %src)372 %2 = call i32 @use_writeonly(ptr nocapture %dest)373 call void @llvm.lifetime.end.p0(ptr nocapture %src)374 call void @llvm.lifetime.end.p0(ptr nocapture %dest)375 ret void376}377 378define void @avoid_memory_use_last_user_crash() {379; CHECK-LABEL: define void @avoid_memory_use_last_user_crash() {380; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4381; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4382; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[SRC]], align 4383; CHECK-NEXT: ret void384;385 %src = alloca %struct.Foo, align 4386 %dest = alloca %struct.Foo, align 4387 call void @llvm.lifetime.start.p0(ptr nocapture %src)388 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src389 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)390 call void @llvm.lifetime.end.p0(ptr nocapture %src)391 %v = load i32, ptr %dest392 ret void393}394 395; For multi-bb patch, we will insert it for next immediate post dominator block.396define void @terminator_lastuse() personality i32 0 {397; CHECK-LABEL: define void @terminator_lastuse() personality i32 0 {398; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4399; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4400; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])401; CHECK-NEXT: [[RV:%.*]] = invoke i32 @use_nocapture(ptr [[SRC]])402; CHECK-NEXT: to label [[SUC:%.*]] unwind label [[UNW:%.*]]403; CHECK: unw:404; CHECK-NEXT: [[LP:%.*]] = landingpad i32405; CHECK-NEXT: cleanup406; CHECK-NEXT: resume i32 0407; CHECK: suc:408; CHECK-NEXT: ret void409;410 %src = alloca %struct.Foo, align 4411 %dest = alloca %struct.Foo, align 4412 call void @llvm.lifetime.start.p0(ptr nocapture %src)413 call void @llvm.lifetime.start.p0(ptr nocapture %dest)414 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src415 %1 = call i32 @use_nocapture(ptr nocapture %src)416 417 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)418 419 call void @llvm.lifetime.end.p0(ptr %src)420 %rv = invoke i32 @use_nocapture(ptr %dest)421 to label %suc unwind label %unw422unw:423 %lp = landingpad i32 cleanup424 resume i32 0425suc:426 ret void427}428 429define void @multi_bb_memcpy(i1 %b) {430; CHECK-LABEL: define void @multi_bb_memcpy431; CHECK-SAME: (i1 [[B:%.*]]) {432; CHECK-NEXT: [[SRC:%.*]] = alloca i32, align 4433; CHECK-NEXT: store i32 42, ptr [[SRC]], align 4434; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])435; CHECK-NEXT: br label [[BB0:%.*]]436; CHECK: bb0:437; CHECK-NEXT: br label [[BB1:%.*]]438; CHECK: bb1:439; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])440; CHECK-NEXT: ret void441;442 %src = alloca i32, align 4443 %dest = alloca i32, align 4444 call void @llvm.lifetime.start.p0(ptr nocapture %src)445 call void @llvm.lifetime.start.p0(ptr nocapture %dest)446 store i32 42, ptr %src447 %1 = call i32 @use_nocapture(ptr nocapture %src)448 br label %bb0449 450bb0:451 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 4, i1 false)452 br label %bb1453 454bb1:455 %2 = call i32 @use_nocapture(ptr nocapture %dest)456 call void @llvm.lifetime.end.p0(ptr nocapture %src)457 call void @llvm.lifetime.end.p0(ptr nocapture %dest)458 ret void459}460 461define void @multi_bb_load_store(i1 %b) {462; CHECK-LABEL: define void @multi_bb_load_store463; CHECK-SAME: (i1 [[B:%.*]]) {464; CHECK-NEXT: [[SRC:%.*]] = alloca i32, align 4465; CHECK-NEXT: store i32 42, ptr [[SRC]], align 4466; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])467; CHECK-NEXT: br label [[BB0:%.*]]468; CHECK: bb0:469; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])470; CHECK-NEXT: ret void471;472 %src = alloca i32, align 4473 %dest = alloca i32, align 4474 call void @llvm.lifetime.start.p0(ptr nocapture %src)475 call void @llvm.lifetime.start.p0(ptr nocapture %dest)476 store i32 42, ptr %src477 %1 = call i32 @use_nocapture(ptr nocapture %src)478 479 %src.val = load i32, ptr %src480 store i32 %src.val, ptr %dest481 br label %bb0482 483bb0:484 %2 = call i32 @use_nocapture(ptr nocapture %dest)485 call void @llvm.lifetime.end.p0(ptr nocapture %src)486 call void @llvm.lifetime.end.p0(ptr nocapture %dest)487 ret void488}489 490; FIXME: merge allocas for bb-separated, but logically straight.491; We might be handle those load/store MemCpyOpt totally492define void @multi_bb_separated_load_store(i1 %b) {493; CHECK-LABEL: define void @multi_bb_separated_load_store494; CHECK-SAME: (i1 [[B:%.*]]) {495; CHECK-NEXT: [[SRC:%.*]] = alloca i32, align 4496; CHECK-NEXT: [[DEST:%.*]] = alloca i32, align 4497; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])498; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])499; CHECK-NEXT: store i32 42, ptr [[SRC]], align 4500; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])501; CHECK-NEXT: [[SRC_VAL:%.*]] = load i32, ptr [[SRC]], align 4502; CHECK-NEXT: br label [[BB0:%.*]]503; CHECK: bb0:504; CHECK-NEXT: store i32 [[SRC_VAL]], ptr [[DEST]], align 4505; CHECK-NEXT: br label [[BB1:%.*]]506; CHECK: bb1:507; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]])508; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])509; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])510; CHECK-NEXT: ret void511;512 %src = alloca i32, align 4513 %dest = alloca i32, align 4514 call void @llvm.lifetime.start.p0(ptr nocapture %src)515 call void @llvm.lifetime.start.p0(ptr nocapture %dest)516 store i32 42, ptr %src517 %1 = call i32 @use_nocapture(ptr nocapture %src)518 519 %src.val = load i32, ptr %src520 br label %bb0521 522bb0:523 store i32 %src.val, ptr %dest524 br label %bb1525 526bb1:527 %2 = call i32 @use_nocapture(ptr nocapture %dest)528 call void @llvm.lifetime.end.p0(ptr nocapture %src)529 call void @llvm.lifetime.end.p0(ptr nocapture %dest)530 ret void531}532 533define void @multi_bb_simple_br(i1 %b) {534; CHECK-LABEL: define void @multi_bb_simple_br535; CHECK-SAME: (i1 [[B:%.*]]) {536; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4537; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4538; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])539; CHECK-NEXT: br i1 [[B]], label [[BB0:%.*]], label [[BB1:%.*]]540; CHECK: bb0:541; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])542; CHECK-NEXT: br label [[BB2:%.*]]543; CHECK: bb1:544; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])545; CHECK-NEXT: br label [[BB2]]546; CHECK: bb2:547; CHECK-NEXT: ret void548;549 %src = alloca %struct.Foo, align 4550 %dest = alloca %struct.Foo, align 4551 call void @llvm.lifetime.start.p0(ptr nocapture %src)552 call void @llvm.lifetime.start.p0(ptr nocapture %dest)553 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src554 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)555 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)556 br i1 %b, label %bb0, label %bb1557 558bb0:559 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)560 br label %bb2561 562bb1:563 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest)564 br label %bb2565 566bb2:567 call void @llvm.lifetime.end.p0(ptr nocapture %src)568 call void @llvm.lifetime.end.p0(ptr nocapture %dest)569 ret void570}571 572; Test for BasicBlock and Instruction mixed dominator finding.573define void @multi_bb_dom_test0(i1 %b) {574; CHECK-LABEL: define void @multi_bb_dom_test0575; CHECK-SAME: (i1 [[B:%.*]]) {576; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4577; CHECK-NEXT: br i1 [[B]], label [[BB0:%.*]], label [[BB1:%.*]]578; CHECK: bb0:579; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4580; CHECK-NEXT: br label [[BB2:%.*]]581; CHECK: bb1:582; CHECK-NEXT: store [[STRUCT_FOO]] { i32 40, i32 50, i32 60 }, ptr [[SRC]], align 4583; CHECK-NEXT: br label [[BB2]]584; CHECK: bb2:585; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])586; CHECK-NEXT: ret void587;588 %src = alloca %struct.Foo, align 4589 %dest = alloca %struct.Foo, align 4590 br i1 %b, label %bb0, label %bb1591 592bb0:593 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src594 br label %bb2595 596bb1:597 store %struct.Foo { i32 40, i32 50, i32 60 }, ptr %src598 br label %bb2599 600bb2:601 call void @llvm.lifetime.start.p0(ptr nocapture %dest)602 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)603 %1 = call i32 @use_nocapture(ptr noundef nocapture %dest)604 605 ret void606 607}608 609; Test for BasicBlock and Instruction mixed dominator finding.610define void @multi_bb_dom_test1(i1 %b) {611; CHECK-LABEL: define void @multi_bb_dom_test1612; CHECK-SAME: (i1 [[B:%.*]]) {613; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4614; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4615; CHECK-NEXT: br i1 [[B]], label [[BB0:%.*]], label [[BB1:%.*]]616; CHECK: bb0:617; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4618; CHECK-NEXT: br label [[BB2:%.*]]619; CHECK: bb1:620; CHECK-NEXT: store [[STRUCT_FOO]] { i32 40, i32 50, i32 60 }, ptr [[SRC]], align 4621; CHECK-NEXT: br label [[BB2]]622; CHECK: bb2:623; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])624; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)625; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[DEST]])626; CHECK-NEXT: ret void627; CHECK: unr:628; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[DEST]])629; CHECK-NEXT: br label [[BB2]]630;631 %src = alloca %struct.Foo, align 4632 %dest = alloca %struct.Foo, align 4633 br i1 %b, label %bb0, label %bb1634 635bb0:636 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src637 br label %bb2638 639bb1:640 store %struct.Foo { i32 40, i32 50, i32 60 }, ptr %src641 br label %bb2642 643bb2:644 call void @llvm.lifetime.start.p0(ptr nocapture %dest)645 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false); 1646 %1 = call i32 @use_nocapture(ptr noundef nocapture %dest)647 648 ret void649 650unr:651 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)652 br label %bb2653}654 655; Test for BasicBlock and Instruction mixed post-dominator finding.656define void @multi_bb_pdom_test0(i1 %b) {657; CHECK-LABEL: define void @multi_bb_pdom_test0658; CHECK-SAME: (i1 [[B:%.*]]) {659; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4660; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4661; CHECK-NEXT: br i1 [[B]], label [[BB0:%.*]], label [[BB1:%.*]]662; CHECK: bb0:663; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])664; CHECK-NEXT: br label [[BB2:%.*]]665; CHECK: bb1:666; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])667; CHECK-NEXT: br label [[BB2]]668; CHECK: bb2:669; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])670; CHECK-NEXT: ret void671;672 %src = alloca %struct.Foo, align 4673 %dest = alloca %struct.Foo, align 4674 call void @llvm.lifetime.start.p0(ptr nocapture %dest)675 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src676 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false); 1677 br i1 %b, label %bb0, label %bb1678 679bb0:680 %1 = call i32 @use_nocapture(ptr noundef nocapture %dest)681 br label %bb2682 683bb1:684 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)685 br label %bb2686 687bb2:688 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest)689 call void @llvm.lifetime.end.p0(ptr nocapture %dest)690 ret void691 692 uselistorder ptr %dest, { 2, 3, 0, 1, 4, 5 }693}694 695; Test for inserting lifetime.end after the phi-node696define void @multi_bb_pdom_test1(i1 %b) {697; CHECK-LABEL: define void @multi_bb_pdom_test1698; CHECK-SAME: (i1 [[B:%.*]]) {699; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4700; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4701; CHECK-NEXT: br i1 [[B]], label [[BB0:%.*]], label [[BB1:%.*]]702; CHECK: bb0:703; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])704; CHECK-NEXT: br label [[BB2:%.*]]705; CHECK: bb1:706; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])707; CHECK-NEXT: br label [[BB2]]708; CHECK: bb2:709; CHECK-NEXT: [[I:%.*]] = phi i32 [ 42, [[BB0]] ], [ 41, [[BB1]] ]710; CHECK-NEXT: ret void711;712 %src = alloca %struct.Foo, align 4713 %dest = alloca %struct.Foo, align 4714 call void @llvm.lifetime.start.p0(ptr nocapture %dest)715 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src716 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false); 1717 br i1 %b, label %bb0, label %bb1718 719bb0:720 %1 = call i32 @use_nocapture(ptr noundef nocapture %dest)721 br label %bb2722 723bb1:724 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)725 br label %bb2726 727bb2:728 %i = phi i32 [ 42, %bb0 ], [ 41, %bb1 ]729 ret void730 731}732 733; Test for existing unreachable cycle734define void @multi_bb_pdom_test2(i1 %b) {735; CHECK-LABEL: define void @multi_bb_pdom_test2736; CHECK-SAME: (i1 [[B:%.*]]) {737; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4738; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4739; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])740; CHECK-NEXT: ret void741; CHECK: unr1:742; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])743; CHECK-NEXT: br label [[UNR2:%.*]]744; CHECK: unr2:745; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])746; CHECK-NEXT: br label [[UNR1:%.*]]747;748 %src = alloca %struct.Foo, align 4749 %dest = alloca %struct.Foo, align 4750 call void @llvm.lifetime.start.p0(ptr nocapture %dest)751 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src752 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false); 1753 %1 = call i32 @use_nocapture(ptr noundef nocapture %dest)754 ret void755 756unr1:757 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)758 br label %unr2759 760unr2:761 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest)762 br label %unr1763 764}765 766define void @multi_bb_loop(i32 %n) {767; CHECK-LABEL: define void @multi_bb_loop768; CHECK-SAME: (i32 [[N:%.*]]) {769; CHECK-NEXT: entry:770; CHECK-NEXT: [[NLT1:%.*]] = icmp slt i32 [[N]], 1771; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 8772; CHECK-NEXT: store [[STRUCT_FOO]] { i32 0, i32 1, i32 42 }, ptr [[SRC]], align 4773; CHECK-NEXT: br i1 [[NLT1]], label [[LOOP_EXIT:%.*]], label [[LOOP_BODY:%.*]]774; CHECK: loop_body:775; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[NEW_I:%.*]], [[LOOP_BODY]] ], [ 1, [[ENTRY:%.*]] ]776; CHECK-NEXT: [[NEW_I]] = add i32 [[I]], 1777; CHECK-NEXT: store i32 [[NEW_I]], ptr [[SRC]], align 4778; CHECK-NEXT: [[IGTN:%.*]] = icmp sgt i32 [[NEW_I]], [[N]]779; CHECK-NEXT: br i1 [[IGTN]], label [[LOOP_EXIT]], label [[LOOP_BODY]]780; CHECK: loop_exit:781; CHECK-NEXT: ret void782;783entry:784 %nlt1 = icmp slt i32 %n, 1785 %src = alloca %struct.Foo, align 8786 %dest = alloca %struct.Foo, align 8787 call void @llvm.lifetime.start.p0(ptr nocapture %src)788 call void @llvm.lifetime.start.p0(ptr nocapture %dest)789 store %struct.Foo { i32 0, i32 1, i32 42 }, ptr %src790 br i1 %nlt1, label %loop_exit, label %loop_body791 792loop_body:793 %i = phi i32 [ %new_i, %loop_body ], [ 1, %entry ]794 call void @llvm.memcpy.p0.p0.i64(ptr align 8 %dest, ptr align 8 %src, i64 12, i1 false)795 %new_i = add i32 %i, 1796 store i32 %new_i, ptr %src797 %igtn = icmp sgt i32 %new_i, %n798 br i1 %igtn, label %loop_exit, label %loop_body799 800loop_exit:801 ret void802}803 804define void @multi_bb_unreachable_modref(i1 %b0) {805; CHECK-LABEL: define void @multi_bb_unreachable_modref806; CHECK-SAME: (i1 [[B0:%.*]]) {807; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4808; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4809; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])810; CHECK-NEXT: br i1 [[B0]], label [[BB0:%.*]], label [[EXIT:%.*]]811; CHECK: exit:812; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])813; CHECK-NEXT: ret void814; CHECK: bb0:815; CHECK-NEXT: ret void816;817 %src = alloca %struct.Foo, align 4818 %dest = alloca %struct.Foo, align 4819 call void @llvm.lifetime.start.p0(ptr nocapture %src)820 call void @llvm.lifetime.start.p0(ptr nocapture %dest)821 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src822 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)823 br i1 %b0, label %bb0, label %exit824 825exit:826 %2 = call i32 @use_nocapture(ptr noundef nocapture %src)827 ret void828 829bb0:830 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)831 call void @llvm.lifetime.end.p0(ptr nocapture %src)832 call void @llvm.lifetime.end.p0(ptr nocapture %dest)833 ret void834}835 836define void @multi_bb_non_dominated(i1 %b0, i1 %b1) {837; CHECK-LABEL: define void @multi_bb_non_dominated838; CHECK-SAME: (i1 [[B0:%.*]], i1 [[B1:%.*]]) {839; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4840; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4841; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])842; CHECK-NEXT: br i1 [[B0]], label [[BB0:%.*]], label [[BB1:%.*]]843; CHECK: bb0:844; CHECK-NEXT: br label [[BB2:%.*]]845; CHECK: bb1:846; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])847; CHECK-NEXT: br label [[BB2]]848; CHECK: bb2:849; CHECK-NEXT: ret void850;851 %src = alloca %struct.Foo, align 4852 %dest = alloca %struct.Foo, align 4853 call void @llvm.lifetime.start.p0(ptr nocapture %src)854 call void @llvm.lifetime.start.p0(ptr nocapture %dest)855 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src856 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)857 br i1 %b0, label %bb0, label %bb1858 859bb0:860 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)861 br label %bb2862 863bb1:864 %2 = call i32 @use_nocapture(ptr noundef nocapture %src)865 br label %bb2866 867bb2:868 call void @llvm.lifetime.end.p0(ptr nocapture %src)869 call void @llvm.lifetime.end.p0(ptr nocapture %dest)870 ret void871}872 873; TODO: to merge following `is_def` cases, we need to do liveness analysis874; or something that distinguish the full-size-Mod as a Def.875; Tests that a memcpy that completely overwrites a stack value is a definition876; for the purposes of liveness analysis.877define void @memcpy_is_def() {878; CHECK-LABEL: define void @memcpy_is_def() {879; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4880; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4881; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])882; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])883; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4884; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])885; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)886; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[DEST]])887; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[SRC]], ptr align 4 [[DEST]], i64 12, i1 false)888; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])889; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])890; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])891; CHECK-NEXT: ret void892;893 %src = alloca %struct.Foo, align 4894 %dest = alloca %struct.Foo, align 4895 call void @llvm.lifetime.start.p0(ptr nocapture %src)896 call void @llvm.lifetime.start.p0(ptr nocapture %dest)897 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src898 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)899 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)900 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)901 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %src, ptr align 4 %dest, i64 12, i1 false)902 %3 = call i32 @use_nocapture(ptr noundef nocapture %src)903 call void @llvm.lifetime.end.p0(ptr nocapture %src)904 call void @llvm.lifetime.end.p0(ptr nocapture %dest)905 ret void906}907 908; TODO: merge allocas909; Tests that a memset that completely overwrites a stack value is a definition910; for the purposes of liveness analysis.911define void @memset_is_def() {912; CHECK-LABEL: define void @memset_is_def() {913; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4914; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4915; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])916; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])917; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4918; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])919; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)920; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[DEST]])921; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[SRC]], i8 42, i64 12, i1 false)922; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])923; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])924; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])925; CHECK-NEXT: ret void926;927 %src = alloca %struct.Foo, align 4928 %dest = alloca %struct.Foo, align 4929 call void @llvm.lifetime.start.p0(ptr nocapture %src)930 call void @llvm.lifetime.start.p0(ptr nocapture %dest)931 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src932 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)933 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)934 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)935 call void @llvm.memset.p0.i64(ptr align 4 %src, i8 42, i64 12, i1 false)936 %3 = call i32 @use_nocapture(ptr noundef nocapture %src)937 call void @llvm.lifetime.end.p0(ptr nocapture %src)938 call void @llvm.lifetime.end.p0(ptr nocapture %dest)939 ret void940}941 942; TODO: merge allocas943; Tests that a store that completely overwrites a stack value is a definition944; for the purposes of liveness analysis.945define void @store_is_def() {946; CHECK-LABEL: define void @store_is_def() {947; CHECK-NEXT: [[SRC:%.*]] = alloca i32, align 4948; CHECK-NEXT: [[DEST:%.*]] = alloca i32, align 4949; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])950; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])951; CHECK-NEXT: store i32 42, ptr [[SRC]], align 4952; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])953; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[SRC]], align 4954; CHECK-NEXT: store i32 [[TMP2]], ptr [[DEST]], align 4955; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[DEST]])956; CHECK-NEXT: store i32 64, ptr [[SRC]], align 4957; CHECK-NEXT: [[TMP4:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])958; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])959; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])960; CHECK-NEXT: ret void961;962 %src = alloca i32, align 4963 %dest = alloca i32, align 4964 call void @llvm.lifetime.start.p0(ptr nocapture %src)965 call void @llvm.lifetime.start.p0(ptr nocapture %dest)966 store i32 42, ptr %src967 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)968 %2 = load i32, ptr %src969 store i32 %2, ptr %dest970 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest)971 store i32 64, ptr %src972 %4 = call i32 @use_nocapture(ptr noundef nocapture %src)973 call void @llvm.lifetime.end.p0(ptr nocapture %src)974 call void @llvm.lifetime.end.p0(ptr nocapture %dest)975 ret void976}977 978; TODO: merge src and dest, because any execution path doesn't cause conflicts.979; Tests that exists modref for both src/dest, but it never conflict on the execution.980define void @multi_bb_dataflow(i1 %b) {981; CHECK-LABEL: define void @multi_bb_dataflow982; CHECK-SAME: (i1 [[B:%.*]]) {983; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4984; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4985; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])986; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])987; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4988; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])989; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)990; CHECK-NEXT: br i1 [[B]], label [[BB0:%.*]], label [[BB1:%.*]]991; CHECK: bb0:992; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])993; CHECK-NEXT: br label [[BB2:%.*]]994; CHECK: bb1:995; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[DEST]])996; CHECK-NEXT: br label [[BB2]]997; CHECK: bb2:998; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])999; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1000; CHECK-NEXT: ret void1001;1002 %src = alloca %struct.Foo, align 41003 %dest = alloca %struct.Foo, align 41004 call void @llvm.lifetime.start.p0(ptr nocapture %src)1005 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1006 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1007 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)1008 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)1009 br i1 %b, label %bb0, label %bb11010 1011bb0:1012 %2 = call i32 @use_nocapture(ptr noundef nocapture %src)1013 br label %bb21014 1015bb1:1016 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest)1017 br label %bb21018 1019bb2:1020 call void @llvm.lifetime.end.p0(ptr nocapture %src)1021 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1022 ret void1023}1024 1025 1026; Optimization failures follow:1027 1028; Tests that a memcpy that doesn't completely overwrite a stack value is a use1029; for the purposes of liveness analysis, not a definition.1030define void @incomplete_memcpy() {1031; CHECK-LABEL: define void @incomplete_memcpy() {1032; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41033; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 41034; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1035; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1036; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41037; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])1038; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 11, i1 false)1039; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[DEST]])1040; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1041; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1042; CHECK-NEXT: ret void1043;1044 %src = alloca %struct.Foo, align 41045 %dest = alloca %struct.Foo, align 41046 call void @llvm.lifetime.start.p0(ptr nocapture %src)1047 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1048 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1049 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)1050 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 11, i1 false)1051 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)1052 call void @llvm.lifetime.end.p0(ptr nocapture %src)1053 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1054 ret void1055}1056 1057; Tests that a store that doesn't completely overwrite a stack value is a use1058; for the purposes of liveness analysis, not a definition.1059define void @incomplete_store() {1060; CHECK-LABEL: define void @incomplete_store() {1061; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41062; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 41063; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1064; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1065; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41066; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])1067; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[SRC]], align 41068; CHECK-NEXT: store i32 [[TMP2]], ptr [[DEST]], align 41069; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[DEST]])1070; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1071; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1072; CHECK-NEXT: ret void1073;1074 %src = alloca %struct.Foo, align 41075 %dest = alloca %struct.Foo, align 41076 call void @llvm.lifetime.start.p0(ptr nocapture %src)1077 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1078 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1079 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)1080 %2 = load i32, ptr %src1081 store i32 %2, ptr %dest1082 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest)1083 call void @llvm.lifetime.end.p0(ptr nocapture %src)1084 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1085 ret void1086}1087 1088; Tests that dynamically-sized allocas are never merged.1089define void @dynamically_sized_alloca(i64 %i) {1090; CHECK-LABEL: define void @dynamically_sized_alloca1091; CHECK-SAME: (i64 [[I:%.*]]) {1092; CHECK-NEXT: [[SRC:%.*]] = alloca i8, i64 [[I]], align 41093; CHECK-NEXT: [[DEST:%.*]] = alloca i8, i64 [[I]], align 41094; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1095; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1096; CHECK-NEXT: store [[STRUCT_FOO:%.*]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41097; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])1098; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)1099; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]])1100; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1101; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1102; CHECK-NEXT: ret void1103;1104 %src = alloca i8, i64 %i, align 41105 %dest = alloca i8, i64 %i, align 41106 call void @llvm.lifetime.start.p0(ptr nocapture %src)1107 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1108 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1109 %1 = call i32 @use_nocapture(ptr nocapture %src)1110 1111 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)1112 1113 %2 = call i32 @use_nocapture(ptr nocapture %dest)1114 call void @llvm.lifetime.end.p0(ptr nocapture %src)1115 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1116 ret void1117}1118 1119 1120; Tests that inalloca attributed allocas are never merged, to prevent stacksave/stackrestore handling.1121define void @inalloca() {1122; CHECK-LABEL: define void @inalloca() {1123; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41124; CHECK-NEXT: [[DEST:%.*]] = alloca inalloca [[STRUCT_FOO]], align 41125; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1126; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1127; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41128; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])1129; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)1130; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]])1131; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1132; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1133; CHECK-NEXT: ret void1134;1135 %src = alloca %struct.Foo, align 41136 %dest = alloca inalloca %struct.Foo, align 41137 call void @llvm.lifetime.start.p0(ptr nocapture %src)1138 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1139 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1140 %1 = call i32 @use_nocapture(ptr nocapture %src)1141 1142 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)1143 1144 %2 = call i32 @use_nocapture(ptr nocapture %dest)1145 call void @llvm.lifetime.end.p0(ptr nocapture %src)1146 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1147 ret void1148}1149 1150; Tests that a memcpy with a dynamic size is never optimized.1151define void @dynamically_sized_memcpy(i64 %size) {1152; CHECK-LABEL: define void @dynamically_sized_memcpy1153; CHECK-SAME: (i64 [[SIZE:%.*]]) {1154; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41155; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 41156; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1157; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1158; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41159; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])1160; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 [[SIZE]], i1 false)1161; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]])1162; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1163; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1164; CHECK-NEXT: ret void1165;1166 %src = alloca %struct.Foo, align 41167 %dest = alloca %struct.Foo, align 41168 call void @llvm.lifetime.start.p0(ptr nocapture %src)1169 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1170 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1171 %1 = call i32 @use_nocapture(ptr nocapture %src)1172 1173 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 %size, i1 false)1174 1175 %2 = call i32 @use_nocapture(ptr nocapture %dest)1176 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1177 call void @llvm.lifetime.end.p0(ptr nocapture %src)1178 ret void1179}1180 1181; Tests that allocas with different sizes aren't merged together.1182define void @mismatched_alloca_size() {1183; CHECK-LABEL: define void @mismatched_alloca_size() {1184; CHECK-NEXT: [[SRC:%.*]] = alloca i8, i64 24, align 41185; CHECK-NEXT: [[DEST:%.*]] = alloca i8, i64 12, align 41186; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1187; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1188; CHECK-NEXT: store [[STRUCT_FOO:%.*]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41189; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])1190; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)1191; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]])1192; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1193; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1194; CHECK-NEXT: ret void1195;1196 %src = alloca i8, i64 24, align 41197 %dest = alloca i8, i64 12, align 41198 call void @llvm.lifetime.start.p0(ptr nocapture %src)1199 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1200 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1201 %1 = call i32 @use_nocapture(ptr nocapture %src)1202 1203 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)1204 1205 %2 = call i32 @use_nocapture(ptr nocapture %dest)1206 call void @llvm.lifetime.end.p0(ptr nocapture %src)1207 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1208 ret void1209}1210 1211; Tests that allocas with mismatched address spaces aren't combined.1212define void @mismatched_alloca_addrspace() {1213; CHECK-LABEL: define void @mismatched_alloca_addrspace() {1214; CHECK-NEXT: [[SRC:%.*]] = alloca i8, i64 24, align 4, addrspace(1)1215; CHECK-NEXT: [[DEST:%.*]] = alloca i8, i64 12, align 4, addrspace(2)1216; CHECK-NEXT: call void @llvm.lifetime.start.p1(ptr addrspace(1) captures(none) [[SRC]])1217; CHECK-NEXT: call void @llvm.lifetime.start.p2(ptr addrspace(2) captures(none) [[DEST]])1218; CHECK-NEXT: store [[STRUCT_FOO:%.*]] { i32 10, i32 20, i32 30 }, ptr addrspace(1) [[SRC]], align 41219; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr addrspace(1) captures(none) [[SRC]])1220; CHECK-NEXT: call void @llvm.memcpy.p2.p1.i64(ptr addrspace(2) align 4 [[DEST]], ptr addrspace(1) align 4 [[SRC]], i64 12, i1 false)1221; CHECK-NEXT: call void @llvm.lifetime.end.p1(ptr addrspace(1) captures(none) [[SRC]])1222; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr addrspace(2) captures(none) [[DEST]])1223; CHECK-NEXT: call void @llvm.lifetime.end.p2(ptr addrspace(2) captures(none) [[DEST]])1224; CHECK-NEXT: ret void1225;1226 %src = alloca i8, i64 24, align 4, addrspace(1)1227 %dest = alloca i8, i64 12, align 4, addrspace(2)1228 call void @llvm.lifetime.start.p1(ptr addrspace(1) nocapture %src)1229 call void @llvm.lifetime.start.p2(ptr addrspace(2) nocapture %dest)1230 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr addrspace(1) %src1231 %1 = call i32 @use_nocapture(ptr addrspace(1) nocapture %src)1232 1233 call void @llvm.memcpy.p2.p1.i64(ptr addrspace(2) align 4 %dest, ptr addrspace(1) align 4 %src, i64 12, i1 false)1234 1235 call void @llvm.lifetime.end.p1(ptr addrspace(1) nocapture %src)1236 %2 = call i32 @use_nocapture(ptr addrspace(2) nocapture %dest)1237 call void @llvm.lifetime.end.p2(ptr addrspace(2) nocapture %dest)1238 ret void1239}1240 1241; Tests that volatile memcpys aren't removed.1242define void @volatile_memcpy() {1243; CHECK-LABEL: define void @volatile_memcpy() {1244; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41245; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 41246; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1247; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1248; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41249; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])1250; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 true)1251; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]])1252; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1253; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1254; CHECK-NEXT: ret void1255;1256 %src = alloca %struct.Foo, align 41257 %dest = alloca %struct.Foo, align 41258 call void @llvm.lifetime.start.p0(ptr nocapture %src)1259 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1260 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1261 %1 = call i32 @use_nocapture(ptr nocapture %src)1262 1263 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 true)1264 1265 %2 = call i32 @use_nocapture(ptr nocapture %dest)1266 call void @llvm.lifetime.end.p0(ptr nocapture %src)1267 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1268 ret void1269}1270 1271; Tests that the optimization isn't performed when the destination is captured.1272define void @dest_captured() {1273; CHECK-LABEL: define void @dest_captured() {1274; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41275; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 41276; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1277; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1278; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41279; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])1280; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)1281; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_maycapture(ptr [[DEST]])1282; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1283; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1284; CHECK-NEXT: ret void1285;1286 %src = alloca %struct.Foo, align 41287 %dest = alloca %struct.Foo, align 41288 call void @llvm.lifetime.start.p0(ptr nocapture %src)1289 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1290 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1291 1292 %1 = call i32 @use_nocapture(ptr nocapture %src)1293 1294 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)1295 %2 = call i32 @use_maycapture(ptr %dest)1296 call void @llvm.lifetime.end.p0(ptr nocapture %src)1297 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1298 ret void1299}1300 1301; Tests that the optimization isn't performed when the source is captured.1302define void @src_captured() {1303; CHECK-LABEL: define void @src_captured() {1304; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41305; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 41306; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1307; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1308; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41309; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_maycapture(ptr [[SRC]])1310; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)1311; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]])1312; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1313; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1314; CHECK-NEXT: ret void1315;1316 %src = alloca %struct.Foo, align 41317 %dest = alloca %struct.Foo, align 41318 call void @llvm.lifetime.start.p0(ptr nocapture %src)1319 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1320 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1321 %1 = call i32 @use_maycapture(ptr %src)1322 1323 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)1324 1325 %2 = call i32 @use_nocapture(ptr nocapture %dest)1326 call void @llvm.lifetime.end.p0(ptr nocapture %src)1327 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1328 ret void1329}1330 1331; Tests that failure if any modref exists before the copy,1332; Exactly ref seems safe because no mod say ref would be always undefined, but to make simple and conservative.1333define void @mod_ref_before_copy() {1334; CHECK-LABEL: define void @mod_ref_before_copy() {1335; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41336; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 41337; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1338; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1339; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41340; CHECK-NEXT: [[R:%.*]] = call i32 @use_readonly(ptr captures(none) [[DEST]])1341; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])1342; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)1343; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1344; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]])1345; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1346; CHECK-NEXT: ret void1347;1348 %src = alloca %struct.Foo, align 41349 %dest = alloca %struct.Foo, align 41350 call void @llvm.lifetime.start.p0(ptr nocapture %src)1351 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1352 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1353 %r = call i32 @use_readonly(ptr nocapture %dest)1354 %1 = call i32 @use_nocapture(ptr nocapture %src)1355 1356 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)1357 1358 call void @llvm.lifetime.end.p0(ptr nocapture %src)1359 %2 = call i32 @use_nocapture(ptr nocapture %dest)1360 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1361 ret void1362}1363 1364; Tests that failure because copy semantics will change if dest is replaced with src.1365define void @mod_dest_before_copy() {1366; CHECK-LABEL: define void @mod_dest_before_copy() {1367; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41368; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 41369; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1370; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1371; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41372; CHECK-NEXT: store i32 13, ptr [[DEST]], align 41373; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])1374; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)1375; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1376; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]])1377; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1378; CHECK-NEXT: ret void1379;1380 %src = alloca %struct.Foo, align 41381 %dest = alloca %struct.Foo, align 41382 call void @llvm.lifetime.start.p0(ptr nocapture %src)1383 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1384 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1385 store i32 13, ptr %dest1386 %1 = call i32 @use_nocapture(ptr nocapture %src)1387 1388 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)1389 1390 call void @llvm.lifetime.end.p0(ptr nocapture %src)1391 %2 = call i32 @use_nocapture(ptr nocapture %dest)1392 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1393 ret void1394}1395 1396define void @mod_src_before_store_after_load() {1397; CHECK-LABEL: define void @mod_src_before_store_after_load() {1398; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41399; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 41400; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1401; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1402; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41403; CHECK-NEXT: store i32 13, ptr [[DEST]], align 41404; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])1405; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)1406; CHECK-NEXT: store [[STRUCT_FOO]] { i32 13, i32 13, i32 13 }, ptr [[SRC]], align 41407; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1408; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]])1409; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1410; CHECK-NEXT: ret void1411;1412 %src = alloca %struct.Foo, align 41413 %dest = alloca %struct.Foo, align 41414 call void @llvm.lifetime.start.p0(ptr nocapture %src)1415 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1416 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1417 store i32 13, ptr %dest1418 %1 = call i32 @use_nocapture(ptr nocapture %src)1419 1420 %src.val = load %struct.Foo, ptr %src1421 store %struct.Foo { i32 13, i32 13, i32 13 }, ptr %src1422 store %struct.Foo %src.val, ptr %dest1423 1424 call void @llvm.lifetime.end.p0(ptr nocapture %src)1425 %2 = call i32 @use_nocapture(ptr nocapture %dest)1426 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1427 ret void1428}1429 1430; Tests that the optimization isn't performed,1431; when the source may have mod and dest may have ref after the full copy.1432define void @src_mod_dest_ref_after_copy() {1433; CHECK-LABEL: define void @src_mod_dest_ref_after_copy() {1434; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41435; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 41436; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1437; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1438; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41439; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)1440; CHECK-NEXT: store [[STRUCT_FOO]] { i32 13, i32 13, i32 13 }, ptr [[SRC]], align 41441; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]])1442; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1443; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1444; CHECK-NEXT: ret void1445;1446 %src = alloca %struct.Foo, align 41447 %dest = alloca %struct.Foo, align 41448 call void @llvm.lifetime.start.p0(ptr nocapture %src)1449 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1450 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1451 1452 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)1453 1454 store %struct.Foo { i32 13, i32 13, i32 13 }, ptr %src1455 %1 = call i32 @use_nocapture(ptr nocapture %dest)1456 call void @llvm.lifetime.end.p0(ptr nocapture %src)1457 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1458 ret void1459}1460 1461; Tests that the optimization isn't performed.1462; Merging dest to src is no longer valid if conflicting Mod/Ref exist.1463define void @src_ref_dest_mod_after_copy() {1464; CHECK-LABEL: define void @src_ref_dest_mod_after_copy() {1465; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41466; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 41467; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1468; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1469; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41470; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)1471; CHECK-NEXT: store [[STRUCT_FOO]] { i32 13, i32 13, i32 13 }, ptr [[DEST]], align 41472; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])1473; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1474; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1475; CHECK-NEXT: ret void1476;1477 %src = alloca %struct.Foo, align 41478 %dest = alloca %struct.Foo, align 41479 call void @llvm.lifetime.start.p0(ptr nocapture %src)1480 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1481 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1482 1483 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)1484 1485 store %struct.Foo { i32 13, i32 13, i32 13 }, ptr %dest1486 %1 = call i32 @use_nocapture(ptr nocapture %src)1487 call void @llvm.lifetime.end.p0(ptr nocapture %src)1488 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1489 ret void1490}1491 1492; Tests that failure because alloca is modified through aliases, which requires recursive user ModRefChecks1493define void @dest_alias_mod_before_copy() {1494; CHECK-LABEL: define void @dest_alias_mod_before_copy() {1495; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41496; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 41497; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1498; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1499; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41500; CHECK-NEXT: [[DEST_ALIAS:%.*]] = getelementptr inbounds [[STRUCT_FOO]], ptr [[DEST]], i64 0, i32 11501; CHECK-NEXT: store i32 13, ptr [[DEST_ALIAS]], align 41502; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])1503; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)1504; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]])1505; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1506; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1507; CHECK-NEXT: ret void1508;1509 %src = alloca %struct.Foo, align 41510 %dest = alloca %struct.Foo, align 41511 call void @llvm.lifetime.start.p0(ptr nocapture %src)1512 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1513 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1514 %dest.alias = getelementptr inbounds %struct.Foo, ptr %dest, i64 0, i32 11515 store i32 13, ptr %dest.alias1516 %1 = call i32 @use_nocapture(ptr nocapture %src)1517 1518 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)1519 1520 %2 = call i32 @use_nocapture(ptr nocapture %dest)1521 call void @llvm.lifetime.end.p0(ptr nocapture %src)1522 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1523 ret void1524}1525 1526; Tests that failure because alloca is modified through aliases, which requires recursive user ModRefChecks1527define void @alias_src_ref_dest_mod_after_copy() {1528; CHECK-LABEL: define void @alias_src_ref_dest_mod_after_copy() {1529; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41530; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 41531; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1532; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1533; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41534; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])1535; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)1536; CHECK-NEXT: [[DEST_ALIAS:%.*]] = getelementptr inbounds [[STRUCT_FOO]], ptr [[DEST]], i64 0, i32 11537; CHECK-NEXT: store i32 13, ptr [[DEST_ALIAS]], align 41538; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]])1539; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1540; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1541; CHECK-NEXT: ret void1542;1543 %src = alloca %struct.Foo, align 41544 %dest = alloca %struct.Foo, align 41545 call void @llvm.lifetime.start.p0(ptr nocapture %src)1546 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1547 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1548 %1 = call i32 @use_nocapture(ptr nocapture %src)1549 1550 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)1551 1552 %dest.alias = getelementptr inbounds %struct.Foo, ptr %dest, i64 0, i32 11553 store i32 13, ptr %dest.alias1554 %2 = call i32 @use_nocapture(ptr nocapture %src)1555 call void @llvm.lifetime.end.p0(ptr nocapture %src)1556 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1557 ret void1558}1559 1560; Tests that the optimization isn't performed when the source and destination1561; have mod ref conflict on bb2.1562define void @multi_bb_dataflow_conflict(i1 %b) {1563; CHECK-LABEL: define void @multi_bb_dataflow_conflict1564; CHECK-SAME: (i1 [[B:%.*]]) {1565; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41566; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 41567; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1568; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1569; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41570; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])1571; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)1572; CHECK-NEXT: br i1 [[B]], label [[BB0:%.*]], label [[BB1:%.*]]1573; CHECK: bb0:1574; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])1575; CHECK-NEXT: br label [[BB2:%.*]]1576; CHECK: bb1:1577; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[DEST]])1578; CHECK-NEXT: br label [[BB2]]1579; CHECK: bb2:1580; CHECK-NEXT: [[TMP4:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[DEST]])1581; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[SRC]])1582; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr captures(none) [[DEST]])1583; CHECK-NEXT: ret void1584;1585 %src = alloca %struct.Foo, align 41586 %dest = alloca %struct.Foo, align 41587 call void @llvm.lifetime.start.p0(ptr nocapture %src)1588 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1589 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1590 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)1591 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)1592 br i1 %b, label %bb0, label %bb11593 1594bb0:1595 %2 = call i32 @use_nocapture(ptr noundef nocapture %src)1596 br label %bb21597 1598bb1:1599 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest)1600 br label %bb21601 1602bb2:1603 %4 = call i32 @use_nocapture(ptr noundef nocapture %dest)1604 call void @llvm.lifetime.end.p0(ptr nocapture %src)1605 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1606 ret void1607}1608 1609; Tests that failure because after copy mod could be before copy on loop.1610define void @multi_bb_loop_dest_mod_before_copy(i32 %n) {1611; CHECK-LABEL: define void @multi_bb_loop_dest_mod_before_copy1612; CHECK-SAME: (i32 [[N:%.*]]) {1613; CHECK-NEXT: entry:1614; CHECK-NEXT: [[NLT1:%.*]] = icmp slt i32 [[N]], 11615; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 81616; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 81617; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[SRC]])1618; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr captures(none) [[DEST]])1619; CHECK-NEXT: store [[STRUCT_FOO]] { i32 0, i32 1, i32 42 }, ptr [[SRC]], align 41620; CHECK-NEXT: br i1 [[NLT1]], label [[LOOP_EXIT:%.*]], label [[LOOP_BODY:%.*]]1621; CHECK: loop_body:1622; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[NEW_I:%.*]], [[LOOP_BODY]] ], [ 1, [[ENTRY:%.*]] ]1623; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[DEST]], ptr align 8 [[SRC]], i64 12, i1 false)1624; CHECK-NEXT: [[NEW_I]] = add i32 [[I]], 11625; CHECK-NEXT: store i32 [[NEW_I]], ptr [[DEST]], align 41626; CHECK-NEXT: [[IGTN:%.*]] = icmp sgt i32 [[NEW_I]], [[N]]1627; CHECK-NEXT: br i1 [[IGTN]], label [[LOOP_EXIT]], label [[LOOP_BODY]]1628; CHECK: loop_exit:1629; CHECK-NEXT: ret void1630;1631entry:1632 %nlt1 = icmp slt i32 %n, 11633 %src = alloca %struct.Foo, align 81634 %dest = alloca %struct.Foo, align 81635 call void @llvm.lifetime.start.p0(ptr nocapture %src)1636 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1637 store %struct.Foo { i32 0, i32 1, i32 42 }, ptr %src1638 br i1 %nlt1, label %loop_exit, label %loop_body1639 1640loop_body:1641 %i = phi i32 [ %new_i, %loop_body ], [ 1, %entry ]1642 call void @llvm.memcpy.p0.p0.i64(ptr align 8 %dest, ptr align 8 %src, i64 12, i1 false)1643 %new_i = add i32 %i, 11644 store i32 %new_i, ptr %dest1645 %igtn = icmp sgt i32 %new_i, %n1646 br i1 %igtn, label %loop_exit, label %loop_body1647 1648loop_exit:1649 ret void1650}1651 1652; Tests that partial-sized lifetimes are not inhibiting the optimizer1653define void @partial_lifetime() {1654; CHECK-LABEL: define void @partial_lifetime() {1655; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41656; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[DEST]], align 41657; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]])1658; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]])1659; CHECK-NEXT: ret void1660;1661 %src = alloca %struct.Foo, align 41662 %dest = alloca %struct.Foo, align 41663 call void @llvm.lifetime.start.p0(ptr nocapture %src)1664 call void @llvm.lifetime.start.p0(ptr nocapture %dest)1665 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1666 %1 = call i32 @use_nocapture(ptr nocapture %src)1667 1668 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)1669 1670 call void @llvm.lifetime.end.p0(ptr nocapture %src)1671 %2 = call i32 @use_nocapture(ptr nocapture %dest)1672 call void @llvm.lifetime.end.p0(ptr nocapture %src)1673 call void @llvm.lifetime.end.p0(ptr nocapture %dest)1674 ret void1675}1676 1677; Do not merge or crash if the different block user comes first.1678define void @crash_store63851(i1 %b) {1679; CHECK-LABEL: define void @crash_store638511680; CHECK-SAME: (i1 [[B:%.*]]) {1681; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO:%.*]], align 81682; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO]], align 81683; CHECK-NEXT: store i32 0, ptr [[DEST]], align 41684; CHECK-NEXT: br i1 [[B]], label [[THEN:%.*]], label [[ELSE:%.*]]1685; CHECK: then:1686; CHECK-NEXT: [[T:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])1687; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[DEST]], ptr [[SRC]], i64 12, i1 false)1688; CHECK-NEXT: [[T3:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]])1689; CHECK-NEXT: [[T4:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[DEST]])1690; CHECK-NEXT: br label [[ELSE]]1691; CHECK: else:1692; CHECK-NEXT: ret void1693;1694 %dest = alloca %struct.Foo, align 81695 %src = alloca %struct.Foo, align 81696 store i32 0, ptr %dest, align 41697 br i1 %b, label %then, label %else1698 1699then: ; preds = %entry1700 %t = call i32 @use_nocapture(ptr nocapture noundef %src)1701 call void @llvm.memcpy.p0.p0.i64(ptr %dest, ptr %src, i64 12, i1 false)1702 %t3 = call i32 @use_nocapture(ptr nocapture noundef %src)1703 %t4 = call i32 @use_nocapture(ptr nocapture noundef %dest)1704 br label %else1705 1706else: ; preds = %then, %entry1707 ret void1708 1709 uselistorder ptr %dest, { 1, 2, 0 }1710}1711 1712declare ptr @captures_ret_only(ptr captures(ret: address, provenance))1713 1714define i32 @test_ret_only_capture() {1715; CHECK-LABEL: define i32 @test_ret_only_capture() {1716; CHECK-NEXT: [[A:%.*]] = alloca i32, align 41717; CHECK-NEXT: [[B:%.*]] = alloca i32, align 41718; CHECK-NEXT: store i32 0, ptr [[A]], align 41719; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[B]], ptr [[A]], i64 4, i1 false)1720; CHECK-NEXT: call void @captures_ret_only(ptr [[B]])1721; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[A]], align 41722; CHECK-NEXT: ret i32 [[V]]1723;1724 %a = alloca i321725 %b = alloca i321726 store i32 0, ptr %a1727 call void @llvm.memcpy(ptr %b, ptr %a, i64 4, i1 false)1728 call void @captures_ret_only(ptr %b)1729 %v = load i32, ptr %a1730 ret i32 %v1731}1732 1733declare ptr @captures_address_only(ptr captures(address))1734 1735; Can transform: Only one address captured.1736define void @test_captures_address_captures_none() {1737; CHECK-LABEL: define void @test_captures_address_captures_none() {1738; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41739; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41740; CHECK-NEXT: call void @captures_address_only(ptr [[SRC]])1741; CHECK-NEXT: call void @use_nocapture(ptr [[SRC]])1742; CHECK-NEXT: ret void1743;1744 %src = alloca %struct.Foo, align 41745 %dst = alloca %struct.Foo, align 41746 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1747 call void @captures_address_only(ptr %src)1748 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dst, ptr align 4 %src, i64 12, i1 false)1749 call void @use_nocapture(ptr %dst)1750 ret void1751}1752 1753; Can transform: Only one address captured.1754define void @test_captures_none_and_captures_address() {1755; CHECK-LABEL: define void @test_captures_none_and_captures_address() {1756; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41757; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41758; CHECK-NEXT: call void @use_nocapture(ptr [[SRC]])1759; CHECK-NEXT: call void @captures_address_only(ptr [[SRC]])1760; CHECK-NEXT: ret void1761;1762 %src = alloca %struct.Foo, align 41763 %dst = alloca %struct.Foo, align 41764 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1765 call void @use_nocapture(ptr %src)1766 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dst, ptr align 4 %src, i64 12, i1 false)1767 call void @captures_address_only(ptr %dst)1768 ret void1769}1770 1771; Cannot transform: Both addresses captured.1772define void @test_captures_address_and_captures_address() {1773; CHECK-LABEL: define void @test_captures_address_and_captures_address() {1774; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 41775; CHECK-NEXT: [[DST:%.*]] = alloca [[STRUCT_FOO]], align 41776; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 41777; CHECK-NEXT: call void @captures_address_only(ptr [[SRC]])1778; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DST]], ptr align 4 [[SRC]], i64 12, i1 false)1779; CHECK-NEXT: call void @captures_address_only(ptr [[DST]])1780; CHECK-NEXT: ret void1781;1782 %src = alloca %struct.Foo, align 41783 %dst = alloca %struct.Foo, align 41784 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src1785 call void @captures_address_only(ptr %src)1786 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dst, ptr align 4 %src, i64 12, i1 false)1787 call void @captures_address_only(ptr %dst)1788 ret void1789}1790