; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 ; RUN: opt -passes='sroa,gvn,instcombine,simplifycfg' -S %s | FileCheck %s %struct.myint4 = type { i32, i32, i32, i32 } define dso_local void @foo_flat(ptr noundef %x, i64 %y.coerce0, i64 %y.coerce1, i32 noundef %cond) { ; CHECK-LABEL: define dso_local void @foo_flat( ; CHECK-SAME: ptr noundef [[X:%.*]], i64 [[Y_COERCE0:%.*]], i64 [[Y_COERCE1:%.*]], i32 noundef [[COND:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[COND]], 0 ; CHECK-NEXT: [[DOTY_COERCE1:%.*]] = select i1 [[TOBOOL_NOT]], i64 0, i64 [[Y_COERCE1]] ; CHECK-NEXT: [[DOTY_COERCE0:%.*]] = select i1 [[TOBOOL_NOT]], i64 0, i64 [[Y_COERCE0]] ; CHECK-NEXT: store i64 [[DOTY_COERCE0]], ptr [[X]], align 16 ; CHECK-NEXT: [[X_REPACK7:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 8 ; CHECK-NEXT: store i64 [[DOTY_COERCE1]], ptr [[X_REPACK7]], align 8 ; CHECK-NEXT: ret void ; entry: %y = alloca %struct.myint4, align 16 %x.addr = alloca ptr, align 8 %cond.addr = alloca i32, align 4 %temp = alloca %struct.myint4, align 16 %zero = alloca %struct.myint4, align 16 %data = alloca %struct.myint4, align 16 %0 = getelementptr inbounds nuw { i64, i64 }, ptr %y, i32 0, i32 0 store i64 %y.coerce0, ptr %0, align 16 %1 = getelementptr inbounds nuw { i64, i64 }, ptr %y, i32 0, i32 1 store i64 %y.coerce1, ptr %1, align 8 store ptr %x, ptr %x.addr, align 8 store i32 %cond, ptr %cond.addr, align 4 call void @llvm.lifetime.start.p0(ptr %temp) call void @llvm.memcpy.p0.p0.i64(ptr align 16 %temp, ptr align 16 %y, i64 16, i1 false) call void @llvm.lifetime.start.p0(ptr %zero) call void @llvm.memset.p0.i64(ptr align 16 %zero, i8 0, i64 16, i1 false) call void @llvm.lifetime.start.p0(ptr %data) %2 = load i32, ptr %cond.addr, align 4 %tobool = icmp ne i32 %2, 0 br i1 %tobool, label %cond.true, label %cond.false cond.true: br label %cond.end cond.false: br label %cond.end cond.end: %cond1 = phi ptr [ %temp, %cond.true ], [ %zero, %cond.false ] %whole = load { i64, i64 }, ptr %cond1, align 16 store { i64, i64 } %whole, ptr %data, align 16 %3 = load ptr, ptr %x.addr, align 8 %whole2 = load { i64, i64 }, ptr %data, align 16 store { i64, i64 } %whole2, ptr %3, align 16 call void @llvm.lifetime.end.p0(ptr %data) call void @llvm.lifetime.end.p0(ptr %zero) call void @llvm.lifetime.end.p0(ptr %temp) ret void } %struct.myint4_base_n = type { i32, i32, i32, i32 } %struct.myint4_nested = type { %struct.myint4_base_n } define dso_local void @foo_nested(ptr noundef %x, i64 %y.coerce0, i64 %y.coerce1, i32 noundef %cond) { ; CHECK-LABEL: define dso_local void @foo_nested( ; CHECK-SAME: ptr noundef [[X:%.*]], i64 [[Y_COERCE0:%.*]], i64 [[Y_COERCE1:%.*]], i32 noundef [[COND:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[COND]], 0 ; CHECK-NEXT: [[DOTY_COERCE1:%.*]] = select i1 [[TOBOOL_NOT]], i64 0, i64 [[Y_COERCE1]] ; CHECK-NEXT: [[DOTY_COERCE0:%.*]] = select i1 [[TOBOOL_NOT]], i64 0, i64 [[Y_COERCE0]] ; CHECK-NEXT: store i64 [[DOTY_COERCE0]], ptr [[X]], align 16 ; CHECK-NEXT: [[X_REPACK7:%.*]] = getelementptr inbounds nuw i8, ptr [[X]], i64 8 ; CHECK-NEXT: store i64 [[DOTY_COERCE1]], ptr [[X_REPACK7]], align 8 ; CHECK-NEXT: ret void ; entry: %y = alloca %struct.myint4_nested, align 16 %x.addr = alloca ptr, align 8 %cond.addr = alloca i32, align 4 %temp = alloca %struct.myint4_nested, align 16 %zero = alloca %struct.myint4_nested, align 16 %data = alloca %struct.myint4_nested, align 16 %0 = getelementptr inbounds nuw { i64, i64 }, ptr %y, i32 0, i32 0 store i64 %y.coerce0, ptr %0, align 16 %1 = getelementptr inbounds nuw { i64, i64 }, ptr %y, i32 0, i32 1 store i64 %y.coerce1, ptr %1, align 8 store ptr %x, ptr %x.addr, align 8 store i32 %cond, ptr %cond.addr, align 4 call void @llvm.lifetime.start.p0(ptr %temp) call void @llvm.memcpy.p0.p0.i64(ptr align 16 %temp, ptr align 16 %y, i64 16, i1 false) call void @llvm.lifetime.start.p0(ptr %zero) call void @llvm.memset.p0.i64(ptr align 16 %zero, i8 0, i64 16, i1 false) call void @llvm.lifetime.start.p0(ptr %data) %2 = load i32, ptr %cond.addr, align 4 %tobool = icmp ne i32 %2, 0 br i1 %tobool, label %cond.true, label %cond.false cond.true: br label %cond.end cond.false: br label %cond.end cond.end: %cond1 = phi ptr [ %temp, %cond.true ], [ %zero, %cond.false ] %whole = load { i64, i64 }, ptr %cond1, align 16 store { i64, i64 } %whole, ptr %data, align 16 %3 = load ptr, ptr %x.addr, align 8 %whole2 = load { i64, i64 }, ptr %data, align 16 store { i64, i64 } %whole2, ptr %3, align 16 call void @llvm.lifetime.end.p0(ptr %data) call void @llvm.lifetime.end.p0(ptr %zero) call void @llvm.lifetime.end.p0(ptr %temp) ret void } %struct.padded = type { i32, i8, i32, i8 } define dso_local void @foo_padded(ptr noundef %x, i32 %a0, i8 %a1, ; CHECK-LABEL: define dso_local void @foo_padded( ; CHECK-SAME: ptr noundef [[X:%.*]], i32 [[A0:%.*]], i8 [[A1:%.*]], i32 [[A2:%.*]], i8 [[A3:%.*]], i32 noundef [[COND:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[TEMP:%.*]] = alloca [[STRUCT_PADDED:%.*]], align 4 ; CHECK-NEXT: [[ZERO:%.*]] = alloca [[STRUCT_PADDED]], align 4 ; CHECK-NEXT: [[DATA:%.*]] = alloca [[STRUCT_PADDED]], align 4 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[TEMP]]) ; CHECK-NEXT: store i32 [[A0]], ptr [[TEMP]], align 4 ; CHECK-NEXT: [[Y_SROA_2_0_TEMP_SROA_IDX:%.*]] = getelementptr inbounds nuw i8, ptr [[TEMP]], i64 4 ; CHECK-NEXT: store i8 [[A1]], ptr [[Y_SROA_2_0_TEMP_SROA_IDX]], align 4 ; CHECK-NEXT: [[Y_SROA_31_0_TEMP_SROA_IDX:%.*]] = getelementptr inbounds nuw i8, ptr [[TEMP]], i64 8 ; CHECK-NEXT: store i32 [[A2]], ptr [[Y_SROA_31_0_TEMP_SROA_IDX]], align 4 ; CHECK-NEXT: [[Y_SROA_4_0_TEMP_SROA_IDX:%.*]] = getelementptr inbounds nuw i8, ptr [[TEMP]], i64 12 ; CHECK-NEXT: store i8 [[A3]], ptr [[Y_SROA_4_0_TEMP_SROA_IDX]], align 4 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[ZERO]]) ; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr noundef nonnull align 4 dereferenceable(16) [[ZERO]], i8 0, i64 16, i1 false) ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[DATA]]) ; CHECK-NEXT: [[TOBOOL_PAD_NOT:%.*]] = icmp eq i32 [[COND]], 0 ; CHECK-NEXT: [[ZERO_TEMP:%.*]] = select i1 [[TOBOOL_PAD_NOT]], ptr [[ZERO]], ptr [[TEMP]] ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(16) [[DATA]], ptr noundef nonnull align 4 dereferenceable(16) [[ZERO_TEMP]], i64 16, i1 false) ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(16) [[X]], ptr noundef nonnull align 4 dereferenceable(16) [[DATA]], i64 16, i1 false) ; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[DATA]]) ; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[ZERO]]) ; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[TEMP]]) ; CHECK-NEXT: ret void ; i32 %a2, i8 %a3, i32 noundef %cond) { entry: %y = alloca %struct.padded, align 4 %x.addr = alloca ptr, align 8 %cond.addr = alloca i32, align 4 %temp = alloca %struct.padded, align 4 %zero = alloca %struct.padded, align 4 %data = alloca %struct.padded, align 4 %y_i32_0 = getelementptr inbounds %struct.padded, ptr %y, i32 0, i32 0 store i32 %a0, ptr %y_i32_0, align 4 %y_i8_1 = getelementptr inbounds %struct.padded, ptr %y, i32 0, i32 1 store i8 %a1, ptr %y_i8_1, align 1 %y_i32_2 = getelementptr inbounds %struct.padded, ptr %y, i32 0, i32 2 store i32 %a2, ptr %y_i32_2, align 4 %y_i8_3 = getelementptr inbounds %struct.padded, ptr %y, i32 0, i32 3 store i8 %a3, ptr %y_i8_3, align 1 store ptr %x, ptr %x.addr, align 8 store i32 %cond, ptr %cond.addr, align 4 call void @llvm.lifetime.start.p0(ptr %temp) call void @llvm.memcpy.p0.p0.i64(ptr align 4 %temp, ptr align 4 %y, i64 16, i1 false) call void @llvm.lifetime.start.p0(ptr %zero) call void @llvm.memset.p0.i64(ptr align 4 %zero, i8 0, i64 16, i1 false) call void @llvm.lifetime.start.p0(ptr %data) %c.pad = load i32, ptr %cond.addr, align 4 %tobool.pad = icmp ne i32 %c.pad, 0 br i1 %tobool.pad, label %cond.true.pad, label %cond.false.pad cond.true.pad: br label %cond.end.pad cond.false.pad: br label %cond.end.pad cond.end.pad: %cond1.pad = phi ptr [ %temp, %cond.true.pad ], [ %zero, %cond.false.pad ] call void @llvm.memcpy.p0.p0.i64(ptr align 4 %data, ptr align 4 %cond1.pad, i64 16, i1 false) %xv.pad = load ptr, ptr %x.addr, align 8 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %xv.pad, ptr align 4 %data, i64 16, i1 false) call void @llvm.lifetime.end.p0(ptr %data) call void @llvm.lifetime.end.p0(ptr %zero) call void @llvm.lifetime.end.p0(ptr %temp) ret void } %struct.nonhomo = type { i32, i64, i32, i64 } define dso_local void @foo_nonhomo(ptr noundef %x, i32 %a0, i64 %a1, ; CHECK-LABEL: define dso_local void @foo_nonhomo( ; CHECK-SAME: ptr noundef [[X:%.*]], i32 [[A0:%.*]], i64 [[A1:%.*]], i32 [[A2:%.*]], i64 [[A3:%.*]], i32 noundef [[COND:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[TEMP:%.*]] = alloca [[STRUCT_NONHOMO:%.*]], align 8 ; CHECK-NEXT: [[ZERO:%.*]] = alloca [[STRUCT_NONHOMO]], align 8 ; CHECK-NEXT: [[DATA:%.*]] = alloca [[STRUCT_NONHOMO]], align 8 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[TEMP]]) ; CHECK-NEXT: store i32 [[A0]], ptr [[TEMP]], align 8 ; CHECK-NEXT: [[Y_SROA_2_0_TEMP_SROA_IDX:%.*]] = getelementptr inbounds nuw i8, ptr [[TEMP]], i64 4 ; CHECK-NEXT: store i64 [[A1]], ptr [[Y_SROA_2_0_TEMP_SROA_IDX]], align 4 ; CHECK-NEXT: [[Y_SROA_3_0_TEMP_SROA_IDX:%.*]] = getelementptr inbounds nuw i8, ptr [[TEMP]], i64 12 ; CHECK-NEXT: store i32 [[A2]], ptr [[Y_SROA_3_0_TEMP_SROA_IDX]], align 4 ; CHECK-NEXT: [[Y_SROA_4_0_TEMP_SROA_IDX:%.*]] = getelementptr inbounds nuw i8, ptr [[TEMP]], i64 16 ; CHECK-NEXT: store i64 [[A3]], ptr [[Y_SROA_4_0_TEMP_SROA_IDX]], align 8 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[ZERO]]) ; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr noundef nonnull align 8 dereferenceable(32) [[ZERO]], i8 0, i64 32, i1 false) ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[DATA]]) ; CHECK-NEXT: [[TOBOOL_NH_NOT:%.*]] = icmp eq i32 [[COND]], 0 ; CHECK-NEXT: [[ZERO_TEMP:%.*]] = select i1 [[TOBOOL_NH_NOT]], ptr [[ZERO]], ptr [[TEMP]] ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(32) [[DATA]], ptr noundef nonnull align 8 dereferenceable(32) [[ZERO_TEMP]], i64 32, i1 false) ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(32) [[X]], ptr noundef nonnull align 8 dereferenceable(32) [[DATA]], i64 32, i1 false) ; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[DATA]]) ; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[ZERO]]) ; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[TEMP]]) ; CHECK-NEXT: ret void ; i32 %a2, i64 %a3, i32 noundef %cond) { entry: %y = alloca %struct.nonhomo, align 8 %x.addr = alloca ptr, align 8 %cond.addr = alloca i32, align 4 %temp = alloca %struct.nonhomo, align 8 %zero = alloca %struct.nonhomo, align 8 %data = alloca %struct.nonhomo, align 8 %y_i32_0n = getelementptr inbounds %struct.nonhomo, ptr %y, i32 0, i32 0 store i32 %a0, ptr %y_i32_0n, align 4 %y_i64_1n = getelementptr inbounds %struct.nonhomo, ptr %y, i32 0, i32 1 store i64 %a1, ptr %y_i64_1n, align 8 %y_i32_2n = getelementptr inbounds %struct.nonhomo, ptr %y, i32 0, i32 2 store i32 %a2, ptr %y_i32_2n, align 4 %y_i64_3n = getelementptr inbounds %struct.nonhomo, ptr %y, i32 0, i32 3 store i64 %a3, ptr %y_i64_3n, align 8 store ptr %x, ptr %x.addr, align 8 store i32 %cond, ptr %cond.addr, align 4 call void @llvm.lifetime.start.p0(ptr %temp) call void @llvm.memcpy.p0.p0.i64(ptr align 8 %temp, ptr align 8 %y, i64 32, i1 false) call void @llvm.lifetime.start.p0(ptr %zero) call void @llvm.memset.p0.i64(ptr align 8 %zero, i8 0, i64 32, i1 false) call void @llvm.lifetime.start.p0(ptr %data) %c.nh = load i32, ptr %cond.addr, align 4 %tobool.nh = icmp ne i32 %c.nh, 0 br i1 %tobool.nh, label %cond.true.nh, label %cond.false.nh cond.true.nh: br label %cond.end.nh cond.false.nh: br label %cond.end.nh cond.end.nh: %cond1.nh = phi ptr [ %temp, %cond.true.nh ], [ %zero, %cond.false.nh ] call void @llvm.memcpy.p0.p0.i64(ptr align 8 %data, ptr align 8 %cond1.nh, i64 32, i1 false) %xv.nh = load ptr, ptr %x.addr, align 8 call void @llvm.memcpy.p0.p0.i64(ptr align 8 %xv.nh, ptr align 8 %data, i64 32, i1 false) call void @llvm.lifetime.end.p0(ptr %data) call void @llvm.lifetime.end.p0(ptr %zero) call void @llvm.lifetime.end.p0(ptr %temp) ret void } %struct.i1x4 = type { i1, i1, i1, i1 } define dso_local void @foo_i1(ptr noundef %x, i64 %dummy0, i64 %dummy1, ; CHECK-LABEL: define dso_local void @foo_i1( ; CHECK-SAME: ptr noundef [[X:%.*]], i64 [[DUMMY0:%.*]], i64 [[DUMMY1:%.*]], i32 noundef [[COND:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[TEMP:%.*]] = alloca [[STRUCT_I1X4:%.*]], align 1 ; CHECK-NEXT: [[ZERO:%.*]] = alloca [[STRUCT_I1X4]], align 1 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[TEMP]]) ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[ZERO]]) ; CHECK-NEXT: store i32 0, ptr [[ZERO]], align 1 ; CHECK-NEXT: [[TOBOOL_I1_NOT:%.*]] = icmp eq i32 [[COND]], 0 ; CHECK-NEXT: [[ZERO_TEMP:%.*]] = select i1 [[TOBOOL_I1_NOT]], ptr [[ZERO]], ptr [[TEMP]] ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ZERO_TEMP]], align 1 ; CHECK-NEXT: store i32 [[TMP0]], ptr [[X]], align 1 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[ZERO]]) ; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[TEMP]]) ; CHECK-NEXT: ret void ; i32 noundef %cond) { entry: %y = alloca %struct.i1x4, align 1 %x.addr = alloca ptr, align 8 %cond.addr = alloca i32, align 4 %temp = alloca %struct.i1x4, align 1 %zero = alloca %struct.i1x4, align 1 %data = alloca %struct.i1x4, align 1 store ptr %x, ptr %x.addr, align 8 store i32 %cond, ptr %cond.addr, align 4 call void @llvm.lifetime.start.p0(ptr %temp) call void @llvm.memcpy.p0.p0.i64(ptr align 1 %temp, ptr align 1 %y, i64 4, i1 false) call void @llvm.lifetime.start.p0(ptr %zero) call void @llvm.memset.p0.i64(ptr align 1 %zero, i8 0, i64 4, i1 false) call void @llvm.lifetime.start.p0(ptr %data) %c.i1 = load i32, ptr %cond.addr, align 4 %tobool.i1 = icmp ne i32 %c.i1, 0 br i1 %tobool.i1, label %cond.true.i1, label %cond.false.i1 cond.true.i1: br label %cond.end.i1 cond.false.i1: br label %cond.end.i1 cond.end.i1: %cond1.i1 = phi ptr [ %temp, %cond.true.i1 ], [ %zero, %cond.false.i1 ] call void @llvm.memcpy.p0.p0.i64(ptr align 1 %data, ptr align 1 %cond1.i1, i64 4, i1 false) %xv.i1 = load ptr, ptr %x.addr, align 8 call void @llvm.memcpy.p0.p0.i64(ptr align 1 %xv.i1, ptr align 1 %data, i64 4, i1 false) call void @llvm.lifetime.end.p0(ptr %data) call void @llvm.lifetime.end.p0(ptr %zero) call void @llvm.lifetime.end.p0(ptr %temp) ret void } %struct.ptr4 = type { ptr, ptr, ptr, ptr } define dso_local void @foo_ptr(ptr noundef %x, ptr %p0, ptr %p1, ; CHECK-LABEL: define dso_local void @foo_ptr( ; CHECK-SAME: ptr noundef [[X:%.*]], ptr [[P0:%.*]], ptr [[P1:%.*]], ptr [[P2:%.*]], ptr [[P3:%.*]], i32 noundef [[COND:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[TEMP:%.*]] = alloca [[STRUCT_PTR4:%.*]], align 8 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[TEMP]]) ; CHECK-NEXT: store ptr [[P0]], ptr [[TEMP]], align 8 ; CHECK-NEXT: [[Y_SROA_2_0_TEMP_SROA_IDX:%.*]] = getelementptr inbounds nuw i8, ptr [[TEMP]], i64 8 ; CHECK-NEXT: store ptr [[P1]], ptr [[Y_SROA_2_0_TEMP_SROA_IDX]], align 8 ; CHECK-NEXT: [[Y_SROA_3_0_TEMP_SROA_IDX:%.*]] = getelementptr inbounds nuw i8, ptr [[TEMP]], i64 16 ; CHECK-NEXT: store ptr [[P2]], ptr [[Y_SROA_3_0_TEMP_SROA_IDX]], align 8 ; CHECK-NEXT: [[Y_SROA_4_0_TEMP_SROA_IDX:%.*]] = getelementptr inbounds nuw i8, ptr [[TEMP]], i64 24 ; CHECK-NEXT: store ptr [[P3]], ptr [[Y_SROA_4_0_TEMP_SROA_IDX]], align 8 ; CHECK-NEXT: [[TOBOOL_PTR_NOT:%.*]] = icmp eq i32 [[COND]], 0 ; CHECK-NEXT: [[DATA_SROA_0_0_COPYLOAD_PRE:%.*]] = load <4 x ptr>, ptr [[TEMP]], align 8 ; CHECK-NEXT: [[DATA_SROA_0_0_COPYLOAD:%.*]] = select i1 [[TOBOOL_PTR_NOT]], <4 x ptr> splat (ptr null), <4 x ptr> [[DATA_SROA_0_0_COPYLOAD_PRE]] ; CHECK-NEXT: store <4 x ptr> [[DATA_SROA_0_0_COPYLOAD]], ptr [[X]], align 8 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[TEMP]]) ; CHECK-NEXT: ret void ; ptr %p2, ptr %p3, i32 noundef %cond) { entry: %y = alloca %struct.ptr4, align 8 %x.addr = alloca ptr, align 8 %cond.addr = alloca i32, align 4 %temp = alloca %struct.ptr4, align 8 %zero = alloca %struct.ptr4, align 8 %data = alloca %struct.ptr4, align 8 %y_p0 = getelementptr inbounds %struct.ptr4, ptr %y, i32 0, i32 0 store ptr %p0, ptr %y_p0, align 8 %y_p1 = getelementptr inbounds %struct.ptr4, ptr %y, i32 0, i32 1 store ptr %p1, ptr %y_p1, align 8 %y_p2 = getelementptr inbounds %struct.ptr4, ptr %y, i32 0, i32 2 store ptr %p2, ptr %y_p2, align 8 %y_p3 = getelementptr inbounds %struct.ptr4, ptr %y, i32 0, i32 3 store ptr %p3, ptr %y_p3, align 8 store ptr %x, ptr %x.addr, align 8 store i32 %cond, ptr %cond.addr, align 4 call void @llvm.lifetime.start.p0(ptr %temp) call void @llvm.memcpy.p0.p0.i64(ptr align 8 %temp, ptr align 8 %y, i64 32, i1 false) call void @llvm.lifetime.start.p0(ptr %zero) call void @llvm.memset.p0.i64(ptr align 8 %zero, i8 0, i64 32, i1 false) call void @llvm.lifetime.start.p0(ptr %data) %c.ptr = load i32, ptr %cond.addr, align 4 %tobool.ptr = icmp ne i32 %c.ptr, 0 br i1 %tobool.ptr, label %cond.true.ptr, label %cond.false.ptr cond.true.ptr: br label %cond.end.ptr cond.false.ptr: br label %cond.end.ptr cond.end.ptr: %cond1.ptr = phi ptr [ %temp, %cond.true.ptr ], [ %zero, %cond.false.ptr ] call void @llvm.memcpy.p0.p0.i64(ptr align 8 %data, ptr align 8 %cond1.ptr, i64 32, i1 false) %xv.ptr = load ptr, ptr %x.addr, align 8 call void @llvm.memcpy.p0.p0.i64(ptr align 8 %xv.ptr, ptr align 8 %data, i64 32, i1 false) call void @llvm.lifetime.end.p0(ptr %data) call void @llvm.lifetime.end.p0(ptr %zero) call void @llvm.lifetime.end.p0(ptr %temp) ret void }