| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: opt -passes='sroa<aggregate-to-vector>,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 |
| } |
| |
| %struct.i5x2 = type { i5, i5 } |
| define void @struct_i5x2_memcpy_into_alloca(ptr %c) { |
| ; CHECK-LABEL: define void @struct_i5x2_memcpy_into_alloca( |
| ; CHECK-SAME: ptr [[C:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[E:%.*]] = alloca [[STRUCT_I5X2:%.*]], align 1 |
| ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[E]], ptr align 1 [[C]], i32 2, i1 true) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %e = alloca %struct.i5x2, align 1 |
| call void @llvm.memcpy.p0.p0.i32(ptr align 1 %e, ptr align 1 %c, i32 2, i1 true) |
| ret void |
| } |
| |
| %struct.i32x3 = type { i32, i32, i32 } |
| define void @struct_i32x3_memcpy_into_alloca(ptr %c) { |
| ; CHECK-LABEL: define void @struct_i32x3_memcpy_into_alloca( |
| ; CHECK-SAME: ptr [[C:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[E_SROA_0:%.*]] = alloca <3 x i32>, align 16 |
| ; CHECK-NEXT: [[E_SROA_0_0_COPYLOAD:%.*]] = load volatile <3 x i32>, ptr [[C]], align 4 |
| ; CHECK-NEXT: store volatile <3 x i32> [[E_SROA_0_0_COPYLOAD]], ptr [[E_SROA_0]], align 16 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %e = alloca %struct.i32x3, align 4 |
| call void @llvm.memcpy.p0.p0.i32(ptr align 4 %e, ptr align 4 %c, i32 12, i1 true) |
| ret void |
| } |