1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 2; RUN: opt < %s -passes=memcpyopt -verify-memoryssa -S | FileCheck %s 3 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(i64, ptr nocapture) 13declare void @llvm.lifetime.end.p0(i64, ptr nocapture) 14declare void @llvm.lifetime.start.p1(i64, ptr addrspace(1) nocapture) 15declare void @llvm.lifetime.end.p1(i64, ptr addrspace(1) nocapture) 16declare void @llvm.lifetime.start.p2(i64, ptr addrspace(2) nocapture) 17declare void @llvm.lifetime.end.p2(i64, 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 4 27; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 28; 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 void 31; 32 %src = alloca %struct.Foo, align 4 33 %dest = alloca %struct.Foo, align 4 34 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 35 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 36 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 37 %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(i64 12, ptr nocapture %src) 44 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 45 ret void 46} 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 4 51; CHECK-NEXT: [[DEST_GEP:%.*]] = getelementptr i64, ptr [[SRC]], i64 -1 52; CHECK-NEXT: [[DEST_USE:%.*]] = load i8, ptr [[DEST_GEP]], align 1 53; CHECK-NEXT: ret i32 0 54; 55 %dest = alloca i1, align 1 56 ; Replacing the use of dest with src causes no domination uses. 57 %dest.gep = getelementptr i64, ptr %dest, i64 -1 58 %dest.use = load i8, ptr %dest.gep, align 1 59 %src = alloca i8, align 4 60 %src.val = load i1, ptr %src, align 4 61 62 store i1 %src.val, ptr %dest, align 1 63 64 ret i32 0 65} 66 67define void @basic_memmove() { 68; CHECK-LABEL: define void @basic_memmove() { 69; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4 70; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 71; 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 void 74; 75 %src = alloca %struct.Foo, align 4 76 %dest = alloca %struct.Foo, align 4 77 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 78 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 79 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 80 %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(i64 12, ptr nocapture %src) 87 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 88 ret void 89} 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 4 95; CHECK-NEXT: store i32 42, ptr [[SRC]], align 4 96; 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 void 99; 100 %src = alloca i32, align 4 101 %dest = alloca i32, align 4 102 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %src) 103 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %dest) 104 store i32 42, ptr %src 105 %1 = call i32 @use_nocapture(ptr nocapture %src) 106 107 %src.val = load i32, ptr %src 108 store i32 %src.val, ptr %dest 109 110 %2 = call i32 @use_nocapture(ptr nocapture %dest) 111 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %src) 112 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %dest) 113 ret void 114} 115 116; Test scalable vectors. 117define void @load_store_scalable(<vscale x 4 x i32> %x) { 118; CHECK-LABEL: define void @load_store_scalable 119; CHECK-SAME: (<vscale x 4 x i32> [[X:%.*]]) { 120; CHECK-NEXT: [[SRC:%.*]] = alloca <vscale x 4 x i32>, align 16 121; CHECK-NEXT: store <vscale x 4 x i32> [[X]], ptr [[SRC]], align 16 122; 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 void 125; 126 %src = alloca <vscale x 4 x i32> 127 %dest = alloca <vscale x 4 x i32> 128 call void @llvm.lifetime.start.p0(i64 -1, ptr nocapture %src) 129 call void @llvm.lifetime.start.p0(i64 -1, ptr nocapture %dest) 130 store <vscale x 4 x i32> %x, ptr %src 131 %1 = call i32 @use_nocapture(ptr nocapture %src) 132 133 %src.val = load <vscale x 4 x i32>, ptr %src 134 store <vscale x 4 x i32> %src.val, ptr %dest 135 136 %2 = call i32 @use_nocapture(ptr nocapture %dest) 137 138 call void @llvm.lifetime.end.p0(i64 -1, ptr nocapture %src) 139 call void @llvm.lifetime.end.p0(i64 -1, ptr nocapture %dest) 140 ret void 141} 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 8 147; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 148; 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 void 151; 152 %src = alloca %struct.Foo, align 4 153 %dest = alloca %struct.Foo, align 8 154 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 155 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 156 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 157 %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(i64 12, ptr nocapture %src) 163 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 164 ret void 165} 166 167; Tests that we correctly remove extra lifetime intrinsics when performing the 168; optimization. 169define void @remove_extra_lifetime_intrinsics() { 170; CHECK-LABEL: define void @remove_extra_lifetime_intrinsics() { 171; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4 172; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 173; 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 void 177; 178 %src = alloca %struct.Foo, align 4 179 %dest = alloca %struct.Foo, align 4 180 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 181 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 182 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 183 %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(i64 12, ptr nocapture %src) 188 %2 = call i32 @use_nocapture(ptr nocapture %dest) 189 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src) 190 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 191 %3 = call i32 @use_nocapture(ptr nocapture %dest) 192 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src) 193 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 194 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 195 ret void 196} 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 4 202; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 203; 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 void 207; 208 %src = alloca %struct.Foo, align 4 209 %dest = alloca %struct.Foo, align 4 210 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 211 %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 void 218} 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 4 224; CHECK-NEXT: [[DEST_ALIAS:%.*]] = getelementptr [[STRUCT_FOO]], ptr [[SRC]], i32 0, i32 0 225; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 226; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]]) 227; CHECK-NEXT: [[SRC_ALIAS:%.*]] = getelementptr [[STRUCT_FOO]], ptr [[SRC]], i32 0, i32 0 228; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]]) 229; CHECK-NEXT: ret void 230; 231 %src = alloca %struct.Foo, align 4 232 %dest = alloca %struct.Foo, align 4 233 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 234 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 235 %dest.alias = getelementptr %struct.Foo, ptr %dest, i32 0, i32 0 236 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 237 %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 0 242 %2 = call i32 @use_nocapture(ptr nocapture %dest) 243 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src) 244 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 245 ret void 246} 247 248; Scope domain 249!0 = !{!0} 250; Scope in that domain 251!1 = !{!1, !0} 252; Scope list 253!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 4 261; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 262; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]]), !alias.scope [[META0:![0-9]+]] 263; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]]) 264; CHECK-NEXT: ret void 265; 266 %src = alloca %struct.Foo, align 4 267 %dest = alloca %struct.Foo, align 4 268 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 269 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 270 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 271 %1 = call i32 @use_nocapture(ptr nocapture %src), !alias.scope !2 272 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(i64 12, ptr nocapture %src) 276 %2 = call i32 @use_nocapture(ptr nocapture %dest), !noalias !2 277 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 278 ret void 279} 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 4 285; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 286; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]]), !alias.scope [[META0]] 287; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]]) 288; CHECK-NEXT: ret void 289; 290 %src = alloca %struct.Foo, align 4, !annotation !3 291 %dest = alloca %struct.Foo, align 4 292 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 293 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 294 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 295 %1 = call i32 @use_nocapture(ptr nocapture %src), !alias.scope !2 296 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 !2 300 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src) 301 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 302 ret void 303} 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 4 310; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 311; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]]), !alias.scope [[META0]] 312; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]]) 313; CHECK-NEXT: ret void 314; 315 %src = alloca %struct.Foo, align 4 316 %dest = alloca %struct.Foo, align 4 317 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 318 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 319 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 320 %1 = call i32 @use_nocapture(ptr nocapture %src), !alias.scope !2 321 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(i64 12, ptr nocapture %src), !alias.scope !2 325 %2 = call i32 @use_nocapture(ptr nocapture %dest), !noalias !2 326 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest), !noalias !2 327 ret void 328} 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 4 334; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 335; 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 void 338; 339 %src = alloca %struct.Foo, align 4 340 %dest = alloca %struct.Foo, align 4 341 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 342 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 343 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 344 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(i64 12, ptr nocapture %src) 350 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 351 ret void 352} 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 4 358; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 359; 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 void 362; 363 %src = alloca %struct.Foo, align 4 364 %dest = alloca %struct.Foo, align 4 365 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 366 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 367 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 368 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(i64 12, ptr nocapture %src) 374 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 375 ret void 376} 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 4 381; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 382; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[SRC]], align 4 383; CHECK-NEXT: ret void 384; 385 %src = alloca %struct.Foo, align 4 386 %dest = alloca %struct.Foo, align 4 387 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 388 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 389 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(i64 12, ptr nocapture %src) 391 %v = load i32, ptr %dest 392 ret void 393} 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 4 399; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 400; 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 i32 405; CHECK-NEXT: cleanup 406; CHECK-NEXT: resume i32 0 407; CHECK: suc: 408; CHECK-NEXT: ret void 409; 410 %src = alloca %struct.Foo, align 4 411 %dest = alloca %struct.Foo, align 4 412 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 413 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 414 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 415 %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(i64 12, ptr %src) 420 %rv = invoke i32 @use_nocapture(ptr %dest) 421 to label %suc unwind label %unw 422unw: 423 %lp = landingpad i32 cleanup 424 resume i32 0 425suc: 426 ret void 427} 428 429define void @multi_bb_memcpy(i1 %b) { 430; CHECK-LABEL: define void @multi_bb_memcpy 431; CHECK-SAME: (i1 [[B:%.*]]) { 432; CHECK-NEXT: [[SRC:%.*]] = alloca i32, align 4 433; CHECK-NEXT: store i32 42, ptr [[SRC]], align 4 434; 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 void 441; 442 %src = alloca i32, align 4 443 %dest = alloca i32, align 4 444 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %src) 445 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %dest) 446 store i32 42, ptr %src 447 %1 = call i32 @use_nocapture(ptr nocapture %src) 448 br label %bb0 449 450bb0: 451 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 4, i1 false) 452 br label %bb1 453 454bb1: 455 %2 = call i32 @use_nocapture(ptr nocapture %dest) 456 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %src) 457 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %dest) 458 ret void 459} 460 461define void @multi_bb_load_store(i1 %b) { 462; CHECK-LABEL: define void @multi_bb_load_store 463; CHECK-SAME: (i1 [[B:%.*]]) { 464; CHECK-NEXT: [[SRC:%.*]] = alloca i32, align 4 465; CHECK-NEXT: store i32 42, ptr [[SRC]], align 4 466; 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 void 471; 472 %src = alloca i32, align 4 473 %dest = alloca i32, align 4 474 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %src) 475 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %dest) 476 store i32 42, ptr %src 477 %1 = call i32 @use_nocapture(ptr nocapture %src) 478 479 %src.val = load i32, ptr %src 480 store i32 %src.val, ptr %dest 481 br label %bb0 482 483bb0: 484 %2 = call i32 @use_nocapture(ptr nocapture %dest) 485 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %src) 486 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %dest) 487 ret void 488} 489 490; FIXME: merge allocas for bb-separated, but logically straight. 491; We might be handle those load/store MemCpyOpt totally 492define void @multi_bb_separated_load_store(i1 %b) { 493; CHECK-LABEL: define void @multi_bb_separated_load_store 494; CHECK-SAME: (i1 [[B:%.*]]) { 495; CHECK-NEXT: [[SRC:%.*]] = alloca i32, align 4 496; CHECK-NEXT: [[DEST:%.*]] = alloca i32, align 4 497; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr captures(none) [[SRC]]) 498; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr captures(none) [[DEST]]) 499; CHECK-NEXT: store i32 42, ptr [[SRC]], align 4 500; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]]) 501; CHECK-NEXT: [[SRC_VAL:%.*]] = load i32, ptr [[SRC]], align 4 502; CHECK-NEXT: br label [[BB0:%.*]] 503; CHECK: bb0: 504; CHECK-NEXT: store i32 [[SRC_VAL]], ptr [[DEST]], align 4 505; 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(i64 4, ptr captures(none) [[SRC]]) 509; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr captures(none) [[DEST]]) 510; CHECK-NEXT: ret void 511; 512 %src = alloca i32, align 4 513 %dest = alloca i32, align 4 514 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %src) 515 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %dest) 516 store i32 42, ptr %src 517 %1 = call i32 @use_nocapture(ptr nocapture %src) 518 519 %src.val = load i32, ptr %src 520 br label %bb0 521 522bb0: 523 store i32 %src.val, ptr %dest 524 br label %bb1 525 526bb1: 527 %2 = call i32 @use_nocapture(ptr nocapture %dest) 528 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %src) 529 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %dest) 530 ret void 531} 532 533define void @multi_bb_simple_br(i1 %b) { 534; CHECK-LABEL: define void @multi_bb_simple_br 535; CHECK-SAME: (i1 [[B:%.*]]) { 536; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4 537; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 538; 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 void 548; 549 %src = alloca %struct.Foo, align 4 550 %dest = alloca %struct.Foo, align 4 551 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 552 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 553 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 554 %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 %bb1 557 558bb0: 559 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest) 560 br label %bb2 561 562bb1: 563 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest) 564 br label %bb2 565 566bb2: 567 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src) 568 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 569 ret void 570} 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_test0 575; CHECK-SAME: (i1 [[B:%.*]]) { 576; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4 577; 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 4 580; CHECK-NEXT: br label [[BB2:%.*]] 581; CHECK: bb1: 582; CHECK-NEXT: store [[STRUCT_FOO]] { i32 40, i32 50, i32 60 }, ptr [[SRC]], align 4 583; 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 void 587; 588 %src = alloca %struct.Foo, align 4 589 %dest = alloca %struct.Foo, align 4 590 br i1 %b, label %bb0, label %bb1 591 592bb0: 593 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 594 br label %bb2 595 596bb1: 597 store %struct.Foo { i32 40, i32 50, i32 60 }, ptr %src 598 br label %bb2 599 600bb2: 601 call void @llvm.lifetime.start.p0(i64 12, 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 void 606 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_test1 612; CHECK-SAME: (i1 [[B:%.*]]) { 613; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4 614; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 615; 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 4 618; CHECK-NEXT: br label [[BB2:%.*]] 619; CHECK: bb1: 620; CHECK-NEXT: store [[STRUCT_FOO]] { i32 40, i32 50, i32 60 }, ptr [[SRC]], align 4 621; CHECK-NEXT: br label [[BB2]] 622; CHECK: bb2: 623; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, 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 void 627; 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 4 632 %dest = alloca %struct.Foo, align 4 633 br i1 %b, label %bb0, label %bb1 634 635bb0: 636 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 637 br label %bb2 638 639bb1: 640 store %struct.Foo { i32 40, i32 50, i32 60 }, ptr %src 641 br label %bb2 642 643bb2: 644 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 645 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false); 1 646 %1 = call i32 @use_nocapture(ptr noundef nocapture %dest) 647 648 ret void 649 650unr: 651 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest) 652 br label %bb2 653} 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_test0 658; CHECK-SAME: (i1 [[B:%.*]]) { 659; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4 660; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 661; 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 void 671; 672 %src = alloca %struct.Foo, align 4 673 %dest = alloca %struct.Foo, align 4 674 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 675 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 676 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false); 1 677 br i1 %b, label %bb0, label %bb1 678 679bb0: 680 %1 = call i32 @use_nocapture(ptr noundef nocapture %dest) 681 br label %bb2 682 683bb1: 684 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest) 685 br label %bb2 686 687bb2: 688 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest) 689 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 690 ret void 691 692 uselistorder ptr %dest, { 2, 3, 0, 1, 4, 5 } 693} 694 695; Test for inserting lifetime.end after the phi-node 696define void @multi_bb_pdom_test1(i1 %b) { 697; CHECK-LABEL: define void @multi_bb_pdom_test1 698; CHECK-SAME: (i1 [[B:%.*]]) { 699; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4 700; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 701; 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 void 711; 712 %src = alloca %struct.Foo, align 4 713 %dest = alloca %struct.Foo, align 4 714 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 715 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 716 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false); 1 717 br i1 %b, label %bb0, label %bb1 718 719bb0: 720 %1 = call i32 @use_nocapture(ptr noundef nocapture %dest) 721 br label %bb2 722 723bb1: 724 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest) 725 br label %bb2 726 727bb2: 728 %i = phi i32 [ 42, %bb0 ], [ 41, %bb1 ] 729 ret void 730 731} 732 733; Test for existing unreachable cycle 734define void @multi_bb_pdom_test2(i1 %b) { 735; CHECK-LABEL: define void @multi_bb_pdom_test2 736; CHECK-SAME: (i1 [[B:%.*]]) { 737; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4 738; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 739; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]]) 740; CHECK-NEXT: ret void 741; 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 4 749 %dest = alloca %struct.Foo, align 4 750 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 751 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 752 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false); 1 753 %1 = call i32 @use_nocapture(ptr noundef nocapture %dest) 754 ret void 755 756unr1: 757 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest) 758 br label %unr2 759 760unr2: 761 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest) 762 br label %unr1 763 764} 765 766define void @multi_bb_loop(i32 %n) { 767; CHECK-LABEL: define void @multi_bb_loop 768; CHECK-SAME: (i32 [[N:%.*]]) { 769; CHECK-NEXT: entry: 770; CHECK-NEXT: [[NLT1:%.*]] = icmp slt i32 [[N]], 1 771; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 8 772; CHECK-NEXT: store [[STRUCT_FOO]] { i32 0, i32 1, i32 42 }, ptr [[SRC]], align 4 773; 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]], 1 777; CHECK-NEXT: store i32 [[NEW_I]], ptr [[SRC]], align 4 778; 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 void 782; 783entry: 784 %nlt1 = icmp slt i32 %n, 1 785 %src = alloca %struct.Foo, align 8 786 %dest = alloca %struct.Foo, align 8 787 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 788 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 789 store %struct.Foo { i32 0, i32 1, i32 42 }, ptr %src 790 br i1 %nlt1, label %loop_exit, label %loop_body 791 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, 1 796 store i32 %new_i, ptr %src 797 %igtn = icmp sgt i32 %new_i, %n 798 br i1 %igtn, label %loop_exit, label %loop_body 799 800loop_exit: 801 ret void 802} 803 804define void @multi_bb_unreachable_modref(i1 %b0) { 805; CHECK-LABEL: define void @multi_bb_unreachable_modref 806; CHECK-SAME: (i1 [[B0:%.*]]) { 807; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4 808; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 809; 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 void 814; CHECK: bb0: 815; CHECK-NEXT: ret void 816; 817 %src = alloca %struct.Foo, align 4 818 %dest = alloca %struct.Foo, align 4 819 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 820 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 821 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 822 %1 = call i32 @use_nocapture(ptr noundef nocapture %src) 823 br i1 %b0, label %bb0, label %exit 824 825exit: 826 %2 = call i32 @use_nocapture(ptr noundef nocapture %src) 827 ret void 828 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(i64 12, ptr nocapture %src) 832 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 833 ret void 834} 835 836define void @multi_bb_non_dominated(i1 %b0, i1 %b1) { 837; CHECK-LABEL: define void @multi_bb_non_dominated 838; CHECK-SAME: (i1 [[B0:%.*]], i1 [[B1:%.*]]) { 839; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4 840; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 841; 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 void 850; 851 %src = alloca %struct.Foo, align 4 852 %dest = alloca %struct.Foo, align 4 853 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 854 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 855 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 856 %1 = call i32 @use_nocapture(ptr noundef nocapture %src) 857 br i1 %b0, label %bb0, label %bb1 858 859bb0: 860 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false) 861 br label %bb2 862 863bb1: 864 %2 = call i32 @use_nocapture(ptr noundef nocapture %src) 865 br label %bb2 866 867bb2: 868 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src) 869 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 870 ret void 871} 872 873; TODO: to merge following `is_def` cases, we need to do liveness analysis 874; or something that distinguish the full-size-Mod as a Def. 875; Tests that a memcpy that completely overwrites a stack value is a definition 876; 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 4 880; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 881; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 882; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 883; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 884; 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(i64 12, ptr captures(none) [[SRC]]) 890; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 891; CHECK-NEXT: ret void 892; 893 %src = alloca %struct.Foo, align 4 894 %dest = alloca %struct.Foo, align 4 895 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 896 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 897 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 898 %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(i64 12, ptr nocapture %src) 904 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 905 ret void 906} 907 908; TODO: merge allocas 909; Tests that a memset that completely overwrites a stack value is a definition 910; 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 4 914; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 915; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 916; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 917; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 918; 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(i64 12, ptr captures(none) [[SRC]]) 924; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 925; CHECK-NEXT: ret void 926; 927 %src = alloca %struct.Foo, align 4 928 %dest = alloca %struct.Foo, align 4 929 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 930 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 931 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 932 %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(i64 12, ptr nocapture %src) 938 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 939 ret void 940} 941 942; TODO: merge allocas 943; Tests that a store that completely overwrites a stack value is a definition 944; 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 4 948; CHECK-NEXT: [[DEST:%.*]] = alloca i32, align 4 949; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr captures(none) [[SRC]]) 950; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr captures(none) [[DEST]]) 951; CHECK-NEXT: store i32 42, ptr [[SRC]], align 4 952; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]]) 953; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[SRC]], align 4 954; CHECK-NEXT: store i32 [[TMP2]], ptr [[DEST]], align 4 955; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[DEST]]) 956; CHECK-NEXT: store i32 64, ptr [[SRC]], align 4 957; CHECK-NEXT: [[TMP4:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]]) 958; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr captures(none) [[SRC]]) 959; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr captures(none) [[DEST]]) 960; CHECK-NEXT: ret void 961; 962 %src = alloca i32, align 4 963 %dest = alloca i32, align 4 964 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %src) 965 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %dest) 966 store i32 42, ptr %src 967 %1 = call i32 @use_nocapture(ptr noundef nocapture %src) 968 %2 = load i32, ptr %src 969 store i32 %2, ptr %dest 970 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest) 971 store i32 64, ptr %src 972 %4 = call i32 @use_nocapture(ptr noundef nocapture %src) 973 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %src) 974 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %dest) 975 ret void 976} 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_dataflow 982; CHECK-SAME: (i1 [[B:%.*]]) { 983; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4 984; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 985; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 986; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 987; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 988; 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(i64 12, ptr captures(none) [[SRC]]) 999; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 1000; CHECK-NEXT: ret void 1001; 1002 %src = alloca %struct.Foo, align 4 1003 %dest = alloca %struct.Foo, align 4 1004 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1005 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1006 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1007 %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 %bb1 1010 1011bb0: 1012 %2 = call i32 @use_nocapture(ptr noundef nocapture %src) 1013 br label %bb2 1014 1015bb1: 1016 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest) 1017 br label %bb2 1018 1019bb2: 1020 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src) 1021 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1022 ret void 1023} 1024 1025 1026; Optimization failures follow: 1027 1028; Tests that a memcpy that doesn't completely overwrite a stack value is a use 1029; 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 4 1033; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 1034; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1035; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1036; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1037; 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(i64 12, ptr captures(none) [[SRC]]) 1041; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 1042; CHECK-NEXT: ret void 1043; 1044 %src = alloca %struct.Foo, align 4 1045 %dest = alloca %struct.Foo, align 4 1046 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1047 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1048 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1049 %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(i64 12, ptr nocapture %src) 1053 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1054 ret void 1055} 1056 1057; Tests that a store that doesn't completely overwrite a stack value is a use 1058; 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 4 1062; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 1063; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1064; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1065; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1066; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]]) 1067; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[SRC]], align 4 1068; CHECK-NEXT: store i32 [[TMP2]], ptr [[DEST]], align 4 1069; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[DEST]]) 1070; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[SRC]]) 1071; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 1072; CHECK-NEXT: ret void 1073; 1074 %src = alloca %struct.Foo, align 4 1075 %dest = alloca %struct.Foo, align 4 1076 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1077 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1078 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1079 %1 = call i32 @use_nocapture(ptr noundef nocapture %src) 1080 %2 = load i32, ptr %src 1081 store i32 %2, ptr %dest 1082 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest) 1083 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src) 1084 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1085 ret void 1086} 1087 1088; Tests that dynamically-sized allocas are never merged. 1089define void @dynamically_sized_alloca(i64 %i) { 1090; CHECK-LABEL: define void @dynamically_sized_alloca 1091; CHECK-SAME: (i64 [[I:%.*]]) { 1092; CHECK-NEXT: [[SRC:%.*]] = alloca i8, i64 [[I]], align 4 1093; CHECK-NEXT: [[DEST:%.*]] = alloca i8, i64 [[I]], align 4 1094; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr captures(none) [[SRC]]) 1095; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr captures(none) [[DEST]]) 1096; CHECK-NEXT: store [[STRUCT_FOO:%.*]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1097; 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(i64 -1, ptr captures(none) [[SRC]]) 1101; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr captures(none) [[DEST]]) 1102; CHECK-NEXT: ret void 1103; 1104 %src = alloca i8, i64 %i, align 4 1105 %dest = alloca i8, i64 %i, align 4 1106 call void @llvm.lifetime.start.p0(i64 -1, ptr nocapture %src) 1107 call void @llvm.lifetime.start.p0(i64 -1, ptr nocapture %dest) 1108 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1109 %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(i64 -1, ptr nocapture %src) 1115 call void @llvm.lifetime.end.p0(i64 -1, ptr nocapture %dest) 1116 ret void 1117} 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 4 1124; CHECK-NEXT: [[DEST:%.*]] = alloca inalloca [[STRUCT_FOO]], align 4 1125; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1126; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1127; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1128; 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(i64 12, ptr captures(none) [[SRC]]) 1132; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 1133; CHECK-NEXT: ret void 1134; 1135 %src = alloca %struct.Foo, align 4 1136 %dest = alloca inalloca %struct.Foo, align 4 1137 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1138 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1139 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1140 %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(i64 12, ptr nocapture %src) 1146 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1147 ret void 1148} 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_memcpy 1153; CHECK-SAME: (i64 [[SIZE:%.*]]) { 1154; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4 1155; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 1156; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1157; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1158; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1159; 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(i64 12, ptr captures(none) [[DEST]]) 1163; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[SRC]]) 1164; CHECK-NEXT: ret void 1165; 1166 %src = alloca %struct.Foo, align 4 1167 %dest = alloca %struct.Foo, align 4 1168 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1169 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1170 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1171 %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(i64 12, ptr nocapture %dest) 1177 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src) 1178 ret void 1179} 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 4 1185; CHECK-NEXT: [[DEST:%.*]] = alloca i8, i64 12, align 4 1186; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr captures(none) [[SRC]]) 1187; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1188; CHECK-NEXT: store [[STRUCT_FOO:%.*]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1189; 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(i64 24, ptr captures(none) [[SRC]]) 1193; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 1194; CHECK-NEXT: ret void 1195; 1196 %src = alloca i8, i64 24, align 4 1197 %dest = alloca i8, i64 12, align 4 1198 call void @llvm.lifetime.start.p0(i64 24, ptr nocapture %src) 1199 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1200 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1201 %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(i64 24, ptr nocapture %src) 1207 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1208 ret void 1209} 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(i64 24, ptr addrspace(1) captures(none) [[SRC]]) 1217; CHECK-NEXT: call void @llvm.lifetime.start.p2(i64 12, ptr addrspace(2) captures(none) [[DEST]]) 1218; CHECK-NEXT: store [[STRUCT_FOO:%.*]] { i32 10, i32 20, i32 30 }, ptr addrspace(1) [[SRC]], align 4 1219; 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(i64 24, 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(i64 12, ptr addrspace(2) captures(none) [[DEST]]) 1224; CHECK-NEXT: ret void 1225; 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(i64 24, ptr addrspace(1) nocapture %src) 1229 call void @llvm.lifetime.start.p2(i64 12, ptr addrspace(2) nocapture %dest) 1230 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr addrspace(1) %src 1231 %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(i64 24, ptr addrspace(1) nocapture %src) 1236 %2 = call i32 @use_nocapture(ptr addrspace(2) nocapture %dest) 1237 call void @llvm.lifetime.end.p2(i64 12, ptr addrspace(2) nocapture %dest) 1238 ret void 1239} 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 4 1245; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 1246; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1247; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1248; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1249; 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(i64 12, ptr captures(none) [[SRC]]) 1253; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 1254; CHECK-NEXT: ret void 1255; 1256 %src = alloca %struct.Foo, align 4 1257 %dest = alloca %struct.Foo, align 4 1258 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1259 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1260 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1261 %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(i64 12, ptr nocapture %src) 1267 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1268 ret void 1269} 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 4 1275; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 1276; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1277; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1278; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1279; 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(i64 12, ptr captures(none) [[SRC]]) 1283; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 1284; CHECK-NEXT: ret void 1285; 1286 %src = alloca %struct.Foo, align 4 1287 %dest = alloca %struct.Foo, align 4 1288 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1289 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1290 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1291 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(i64 12, ptr nocapture %src) 1297 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1298 ret void 1299} 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 4 1305; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 1306; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1307; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1308; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1309; 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(i64 12, ptr captures(none) [[SRC]]) 1313; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 1314; CHECK-NEXT: ret void 1315; 1316 %src = alloca %struct.Foo, align 4 1317 %dest = alloca %struct.Foo, align 4 1318 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1319 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1320 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1321 %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(i64 12, ptr nocapture %src) 1327 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1328 ret void 1329} 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 4 1336; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 1337; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1338; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1339; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1340; 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(i64 12, 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(i64 12, ptr captures(none) [[DEST]]) 1346; CHECK-NEXT: ret void 1347; 1348 %src = alloca %struct.Foo, align 4 1349 %dest = alloca %struct.Foo, align 4 1350 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1351 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1352 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1353 %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(i64 12, ptr nocapture %src) 1359 %2 = call i32 @use_nocapture(ptr nocapture %dest) 1360 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1361 ret void 1362} 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 4 1368; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 1369; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1370; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1371; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1372; CHECK-NEXT: store i32 13, ptr [[DEST]], align 4 1373; 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(i64 12, 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(i64 12, ptr captures(none) [[DEST]]) 1378; CHECK-NEXT: ret void 1379; 1380 %src = alloca %struct.Foo, align 4 1381 %dest = alloca %struct.Foo, align 4 1382 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1383 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1384 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1385 store i32 13, ptr %dest 1386 %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(i64 12, ptr nocapture %src) 1391 %2 = call i32 @use_nocapture(ptr nocapture %dest) 1392 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1393 ret void 1394} 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 4 1399; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 1400; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1401; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1402; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1403; CHECK-NEXT: store i32 13, ptr [[DEST]], align 4 1404; 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 4 1407; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, 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(i64 12, ptr captures(none) [[DEST]]) 1410; CHECK-NEXT: ret void 1411; 1412 %src = alloca %struct.Foo, align 4 1413 %dest = alloca %struct.Foo, align 4 1414 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1415 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1416 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1417 store i32 13, ptr %dest 1418 %1 = call i32 @use_nocapture(ptr nocapture %src) 1419 1420 %src.val = load %struct.Foo, ptr %src 1421 store %struct.Foo { i32 13, i32 13, i32 13 }, ptr %src 1422 store %struct.Foo %src.val, ptr %dest 1423 1424 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src) 1425 %2 = call i32 @use_nocapture(ptr nocapture %dest) 1426 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1427 ret void 1428} 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 4 1435; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 1436; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1437; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1438; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1439; 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 4 1441; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]]) 1442; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[SRC]]) 1443; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 1444; CHECK-NEXT: ret void 1445; 1446 %src = alloca %struct.Foo, align 4 1447 %dest = alloca %struct.Foo, align 4 1448 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1449 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1450 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1451 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 %src 1455 %1 = call i32 @use_nocapture(ptr nocapture %dest) 1456 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src) 1457 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1458 ret void 1459} 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 4 1466; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 1467; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1468; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1469; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1470; 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 4 1472; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]]) 1473; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[SRC]]) 1474; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 1475; CHECK-NEXT: ret void 1476; 1477 %src = alloca %struct.Foo, align 4 1478 %dest = alloca %struct.Foo, align 4 1479 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1480 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1481 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1482 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 %dest 1486 %1 = call i32 @use_nocapture(ptr nocapture %src) 1487 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src) 1488 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1489 ret void 1490} 1491 1492; Tests that failure because alloca is modified through aliases, which requires recursive user ModRefChecks 1493define void @dest_alias_mod_before_copy() { 1494; CHECK-LABEL: define void @dest_alias_mod_before_copy() { 1495; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4 1496; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 1497; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1498; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1499; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1500; CHECK-NEXT: [[DEST_ALIAS:%.*]] = getelementptr inbounds [[STRUCT_FOO]], ptr [[DEST]], i64 0, i32 1 1501; CHECK-NEXT: store i32 13, ptr [[DEST_ALIAS]], align 4 1502; 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(i64 12, ptr captures(none) [[SRC]]) 1506; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 1507; CHECK-NEXT: ret void 1508; 1509 %src = alloca %struct.Foo, align 4 1510 %dest = alloca %struct.Foo, align 4 1511 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1512 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1513 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1514 %dest.alias = getelementptr inbounds %struct.Foo, ptr %dest, i64 0, i32 1 1515 store i32 13, ptr %dest.alias 1516 %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(i64 12, ptr nocapture %src) 1522 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1523 ret void 1524} 1525 1526; Tests that failure because alloca is modified through aliases, which requires recursive user ModRefChecks 1527define 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 4 1530; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 1531; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1532; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1533; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1534; 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 1 1537; CHECK-NEXT: store i32 13, ptr [[DEST_ALIAS]], align 4 1538; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]]) 1539; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[SRC]]) 1540; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 1541; CHECK-NEXT: ret void 1542; 1543 %src = alloca %struct.Foo, align 4 1544 %dest = alloca %struct.Foo, align 4 1545 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1546 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1547 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1548 %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 1 1553 store i32 13, ptr %dest.alias 1554 %2 = call i32 @use_nocapture(ptr nocapture %src) 1555 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src) 1556 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1557 ret void 1558} 1559 1560; Tests that the optimization isn't performed when the source and destination 1561; have mod ref conflict on bb2. 1562define void @multi_bb_dataflow_conflict(i1 %b) { 1563; CHECK-LABEL: define void @multi_bb_dataflow_conflict 1564; CHECK-SAME: (i1 [[B:%.*]]) { 1565; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4 1566; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 1567; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1568; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1569; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1570; 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(i64 12, ptr captures(none) [[SRC]]) 1582; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 1583; CHECK-NEXT: ret void 1584; 1585 %src = alloca %struct.Foo, align 4 1586 %dest = alloca %struct.Foo, align 4 1587 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1588 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1589 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1590 %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 %bb1 1593 1594bb0: 1595 %2 = call i32 @use_nocapture(ptr noundef nocapture %src) 1596 br label %bb2 1597 1598bb1: 1599 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest) 1600 br label %bb2 1601 1602bb2: 1603 %4 = call i32 @use_nocapture(ptr noundef nocapture %dest) 1604 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src) 1605 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1606 ret void 1607} 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_copy 1612; CHECK-SAME: (i32 [[N:%.*]]) { 1613; CHECK-NEXT: entry: 1614; CHECK-NEXT: [[NLT1:%.*]] = icmp slt i32 [[N]], 1 1615; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 8 1616; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 8 1617; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1618; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[DEST]]) 1619; CHECK-NEXT: store [[STRUCT_FOO]] { i32 0, i32 1, i32 42 }, ptr [[SRC]], align 4 1620; 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]], 1 1625; CHECK-NEXT: store i32 [[NEW_I]], ptr [[DEST]], align 4 1626; 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 void 1630; 1631entry: 1632 %nlt1 = icmp slt i32 %n, 1 1633 %src = alloca %struct.Foo, align 8 1634 %dest = alloca %struct.Foo, align 8 1635 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1636 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest) 1637 store %struct.Foo { i32 0, i32 1, i32 42 }, ptr %src 1638 br i1 %nlt1, label %loop_exit, label %loop_body 1639 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, 1 1644 store i32 %new_i, ptr %dest 1645 %igtn = icmp sgt i32 %new_i, %n 1646 br i1 %igtn, label %loop_exit, label %loop_body 1647 1648loop_exit: 1649 ret void 1650} 1651 1652; Tests that failure because partial-sized lifetimes are counted as mod. 1653define void @partial_lifetime() { 1654; CHECK-LABEL: define void @partial_lifetime() { 1655; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4 1656; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4 1657; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr captures(none) [[SRC]]) 1658; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 3, ptr captures(none) [[DEST]]) 1659; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4 1660; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr captures(none) [[SRC]]) 1661; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false) 1662; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 3, ptr captures(none) [[SRC]]) 1663; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr captures(none) [[DEST]]) 1664; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[SRC]]) 1665; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr captures(none) [[DEST]]) 1666; CHECK-NEXT: ret void 1667; 1668 %src = alloca %struct.Foo, align 4 1669 %dest = alloca %struct.Foo, align 4 1670 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src) 1671 call void @llvm.lifetime.start.p0(i64 3, ptr nocapture %dest) 1672 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src 1673 %1 = call i32 @use_nocapture(ptr nocapture %src) 1674 1675 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false) 1676 1677 call void @llvm.lifetime.end.p0(i64 3, ptr nocapture %src) 1678 %2 = call i32 @use_nocapture(ptr nocapture %dest) 1679 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src) 1680 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest) 1681 ret void 1682} 1683 1684; Do not merge or crash if the different block user comes first. 1685define void @crash_store63851(i1 %b) { 1686; CHECK-LABEL: define void @crash_store63851 1687; CHECK-SAME: (i1 [[B:%.*]]) { 1688; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO:%.*]], align 8 1689; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO]], align 8 1690; CHECK-NEXT: store i32 0, ptr [[DEST]], align 4 1691; CHECK-NEXT: br i1 [[B]], label [[THEN:%.*]], label [[ELSE:%.*]] 1692; CHECK: then: 1693; CHECK-NEXT: [[T:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]]) 1694; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[DEST]], ptr [[SRC]], i64 12, i1 false) 1695; CHECK-NEXT: [[T3:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[SRC]]) 1696; CHECK-NEXT: [[T4:%.*]] = call i32 @use_nocapture(ptr noundef captures(none) [[DEST]]) 1697; CHECK-NEXT: br label [[ELSE]] 1698; CHECK: else: 1699; CHECK-NEXT: ret void 1700; 1701 %dest = alloca %struct.Foo, align 8 1702 %src = alloca %struct.Foo, align 8 1703 store i32 0, ptr %dest, align 4 1704 br i1 %b, label %then, label %else 1705 1706then: ; preds = %entry 1707 %t = call i32 @use_nocapture(ptr nocapture noundef %src) 1708 call void @llvm.memcpy.p0.p0.i64(ptr %dest, ptr %src, i64 12, i1 false) 1709 %t3 = call i32 @use_nocapture(ptr nocapture noundef %src) 1710 %t4 = call i32 @use_nocapture(ptr nocapture noundef %dest) 1711 br label %else 1712 1713else: ; preds = %then, %entry 1714 ret void 1715 1716 uselistorder ptr %dest, { 1, 2, 0 } 1717} 1718