From ee4e3e40750d9bf7f3b67aca4759a00dc5fee64e Mon Sep 17 00:00:00 2001 From: John McCall Date: Mon, 29 Oct 2018 20:32:36 +0000 Subject: [PATCH] In swiftcall, don't merge FP/vector types within a chunk. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@345536 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/CodeGen/SwiftCallingConv.h | 3 + lib/CodeGen/SwiftCallingConv.cpp | 40 +++++++++- test/CodeGen/64bit-swiftcall.c | 93 ++++++++++++++---------- test/CodeGen/windows-swiftcall.c | 77 ++++++++++++-------- 4 files changed, 140 insertions(+), 73 deletions(-) diff --git a/include/clang/CodeGen/SwiftCallingConv.h b/include/clang/CodeGen/SwiftCallingConv.h index 45b3145ed9..5aa9be2d67 100644 --- a/include/clang/CodeGen/SwiftCallingConv.h +++ b/include/clang/CodeGen/SwiftCallingConv.h @@ -114,6 +114,9 @@ private: void addLegalTypedData(llvm::Type *type, CharUnits begin, CharUnits end); void addEntry(llvm::Type *type, CharUnits begin, CharUnits end); void splitVectorEntry(unsigned index); + static bool shouldMergeEntries(const StorageEntry &first, + const StorageEntry &second, + CharUnits chunkSize); }; /// Should an aggregate which expands to the given type sequence diff --git a/lib/CodeGen/SwiftCallingConv.cpp b/lib/CodeGen/SwiftCallingConv.cpp index b411a501ea..75a0fa5ce1 100644 --- a/lib/CodeGen/SwiftCallingConv.cpp +++ b/lib/CodeGen/SwiftCallingConv.cpp @@ -415,6 +415,40 @@ static bool areBytesInSameUnit(CharUnits first, CharUnits second, == getOffsetAtStartOfUnit(second, chunkSize); } +static bool isMergeableEntryType(llvm::Type *type) { + // Opaquely-typed memory is always mergeable. + if (type == nullptr) return true; + + // Pointers and integers are always mergeable. In theory we should not + // merge pointers, but (1) it doesn't currently matter in practice because + // the chunk size is never greater than the size of a pointer and (2) + // Swift IRGen uses integer types for a lot of things that are "really" + // just storing pointers (like Optional). If we ever have a + // target that would otherwise combine pointers, we should put some effort + // into fixing those cases in Swift IRGen and then call out pointer types + // here. + + // Floating-point and vector types should never be merged. + // Most such types are too large and highly-aligned to ever trigger merging + // in practice, but it's important for the rule to cover at least 'half' + // and 'float', as well as things like small vectors of 'i1' or 'i8'. + return (!type->isFloatingPointTy() && !type->isVectorTy()); +} + +bool SwiftAggLowering::shouldMergeEntries(const StorageEntry &first, + const StorageEntry &second, + CharUnits chunkSize) { + // Only merge entries that overlap the same chunk. We test this first + // despite being a bit more expensive because this is the condition that + // tends to prevent merging. + if (!areBytesInSameUnit(first.End - CharUnits::One(), second.Begin, + chunkSize)) + return false; + + return (isMergeableEntryType(first.Type) && + isMergeableEntryType(second.Type)); +} + void SwiftAggLowering::finish() { if (Entries.empty()) { Finished = true; @@ -425,12 +459,12 @@ void SwiftAggLowering::finish() { // which is generally the size of a pointer. const CharUnits chunkSize = getMaximumVoluntaryIntegerSize(CGM); - // First pass: if two entries share a chunk, make them both opaque + // First pass: if two entries should be merged, make them both opaque // and stretch one to meet the next. + // Also, remember if there are any opaque entries. bool hasOpaqueEntries = (Entries[0].Type == nullptr); for (size_t i = 1, e = Entries.size(); i != e; ++i) { - if (areBytesInSameUnit(Entries[i - 1].End - CharUnits::One(), - Entries[i].Begin, chunkSize)) { + if (shouldMergeEntries(Entries[i - 1], Entries[i], chunkSize)) { Entries[i - 1].Type = nullptr; Entries[i].Type = nullptr; Entries[i - 1].End = Entries[i].Begin; diff --git a/test/CodeGen/64bit-swiftcall.c b/test/CodeGen/64bit-swiftcall.c index 7486e44406..6175553ec9 100644 --- a/test/CodeGen/64bit-swiftcall.c +++ b/test/CodeGen/64bit-swiftcall.c @@ -10,7 +10,7 @@ #define ERROR __attribute__((swift_error_result)) #define CONTEXT __attribute__((swift_context)) -// CHECK: [[STRUCT2_RESULT:@.*]] = private {{.*}} constant [[STRUCT2_TYPE:%.*]] { i32 0, i8 0, i8 undef, i8 0, float 0.000000e+00, float 0.000000e+00 } +// CHECK: [[STRUCT2_RESULT:@.*]] = private {{.*}} constant [[STRUCT2_TYPE:%.*]] { i32 0, i8 0, i8 undef, i8 0, i32 0, i32 0 } /*****************************************************************************/ /****************************** PARAMETER ABIS *******************************/ @@ -102,8 +102,8 @@ typedef struct { int x; char c0; char c1; - float f0; - float f1; + int f0; + int f1; } struct_1; TEST(struct_1); // CHECK-LABEL: define swiftcc { i64, i64 } @return_struct_1() {{.*}}{ @@ -150,8 +150,8 @@ typedef struct { int x; char c0; __attribute__((aligned(2))) char c1; - float f0; - float f1; + int f0; + int f1; } struct_2; TEST(struct_2); // CHECK-LABEL: define swiftcc { i64, i64 } @return_struct_2() {{.*}}{ @@ -308,20 +308,30 @@ typedef union { TEST(union_hom_fp_partial) // CHECK: define void @test_union_hom_fp_partial() // CHECK: [[AGG:%.*]] = alloca [[UNION:%.*]], align 16 -// CHECK: [[CALL:%.*]] = call swiftcc { i64, i64 } @return_union_hom_fp_partial() -// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { i64, i64 }* -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 0 -// CHECK: [[T1:%.*]] = extractvalue { i64, i64 } [[CALL]], 0 -// CHECK: store i64 [[T1]], i64* [[T0]], align 16 -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 1 -// CHECK: [[T1:%.*]] = extractvalue { i64, i64 } [[CALL]], 1 -// CHECK: store i64 [[T1]], i64* [[T0]], align 8 -// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { i64, i64 }* -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 0 -// CHECK: [[V0:%.*]] = load i64, i64* [[T0]], align 16 -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 1 -// CHECK: [[V1:%.*]] = load i64, i64* [[T0]], align 8 -// CHECK: call swiftcc void @take_union_hom_fp_partial(i64 [[V0]], i64 [[V1]]) +// CHECK: [[CALL:%.*]] = call swiftcc { float, float, float, float } @return_union_hom_fp_partial() +// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { float, float, float, float }* +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 0 +// CHECK: [[T1:%.*]] = extractvalue { float, float, float, float } [[CALL]], 0 +// CHECK: store float [[T1]], float* [[T0]], align 16 +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 1 +// CHECK: [[T1:%.*]] = extractvalue { float, float, float, float } [[CALL]], 1 +// CHECK: store float [[T1]], float* [[T0]], align 4 +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 2 +// CHECK: [[T1:%.*]] = extractvalue { float, float, float, float } [[CALL]], 2 +// CHECK: store float [[T1]], float* [[T0]], align 8 +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 3 +// CHECK: [[T1:%.*]] = extractvalue { float, float, float, float } [[CALL]], 3 +// CHECK: store float [[T1]], float* [[T0]], align 4 +// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { float, float, float, float }* +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 0 +// CHECK: [[V0:%.*]] = load float, float* [[T0]], align 16 +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 1 +// CHECK: [[V1:%.*]] = load float, float* [[T0]], align 4 +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 2 +// CHECK: [[V2:%.*]] = load float, float* [[T0]], align 8 +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 3 +// CHECK: [[V3:%.*]] = load float, float* [[T0]], align 4 +// CHECK: call swiftcc void @take_union_hom_fp_partial(float [[V0]], float [[V1]], float [[V2]], float [[V3]]) // CHECK: ret void // CHECK: } @@ -332,20 +342,25 @@ typedef union { TEST(union_het_fpv_partial) // CHECK-LABEL: define void @test_union_het_fpv_partial() // CHECK: [[AGG:%.*]] = alloca [[UNION:%.*]], align 16 -// CHECK: [[CALL:%.*]] = call swiftcc { i64, i64 } @return_union_het_fpv_partial() -// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { i64, i64 }* -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 0 -// CHECK: [[T1:%.*]] = extractvalue { i64, i64 } [[CALL]], 0 +// CHECK: [[CALL:%.*]] = call swiftcc { i64, float, float } @return_union_het_fpv_partial() +// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { i64, float, float }* +// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, float, float }, { i64, float, float }* [[CAST]], i32 0, i32 0 +// CHECK: [[T1:%.*]] = extractvalue { i64, float, float } [[CALL]], 0 // CHECK: store i64 [[T1]], i64* [[T0]], align 16 -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 1 -// CHECK: [[T1:%.*]] = extractvalue { i64, i64 } [[CALL]], 1 -// CHECK: store i64 [[T1]], i64* [[T0]], align 8 -// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { i64, i64 }* -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 0 +// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, float, float }, { i64, float, float }* [[CAST]], i32 0, i32 1 +// CHECK: [[T1:%.*]] = extractvalue { i64, float, float } [[CALL]], 1 +// CHECK: store float [[T1]], float* [[T0]], align 8 +// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, float, float }, { i64, float, float }* [[CAST]], i32 0, i32 2 +// CHECK: [[T1:%.*]] = extractvalue { i64, float, float } [[CALL]], 2 +// CHECK: store float [[T1]], float* [[T0]], align 4 +// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { i64, float, float }* +// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, float, float }, { i64, float, float }* [[CAST]], i32 0, i32 0 // CHECK: [[V0:%.*]] = load i64, i64* [[T0]], align 16 -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 1 -// CHECK: [[V1:%.*]] = load i64, i64* [[T0]], align 8 -// CHECK: call swiftcc void @take_union_het_fpv_partial(i64 [[V0]], i64 [[V1]]) +// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, float, float }, { i64, float, float }* [[CAST]], i32 0, i32 1 +// CHECK: [[V1:%.*]] = load float, float* [[T0]], align 8 +// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, float, float }, { i64, float, float }* [[CAST]], i32 0, i32 2 +// CHECK: [[V2:%.*]] = load float, float* [[T0]], align 4 +// CHECK: call swiftcc void @take_union_het_fpv_partial(i64 [[V0]], float [[V1]], float [[V2]]) // CHECK: ret void // CHECK: } @@ -464,8 +479,8 @@ typedef struct { float f1; } struct_f2; TEST(struct_f2) -// CHECK-LABEL: define swiftcc i64 @return_struct_f2() -// CHECK-LABEL: define swiftcc void @take_struct_f2(i64) +// CHECK-LABEL: define swiftcc { float, float } @return_struct_f2() +// CHECK-LABEL: define swiftcc void @take_struct_f2(float, float) typedef struct { float f0; @@ -473,8 +488,8 @@ typedef struct { float f2; } struct_f3; TEST(struct_f3) -// CHECK-LABEL: define swiftcc { i64, float } @return_struct_f3() -// CHECK-LABEL: define swiftcc void @take_struct_f3(i64, float) +// CHECK-LABEL: define swiftcc { float, float, float } @return_struct_f3() +// CHECK-LABEL: define swiftcc void @take_struct_f3(float, float, float) typedef struct { float f0; @@ -483,8 +498,8 @@ typedef struct { float f3; } struct_f4; TEST(struct_f4) -// CHECK-LABEL: define swiftcc { i64, i64 } @return_struct_f4() -// CHECK-LABEL: define swiftcc void @take_struct_f4(i64, i64) +// CHECK-LABEL: define swiftcc { float, float, float, float } @return_struct_f4() +// CHECK-LABEL: define swiftcc void @take_struct_f4(float, float, float, float) typedef struct { @@ -1016,8 +1031,8 @@ typedef union { float3 fv2; } union_hom_fp_partial2; TEST(union_hom_fp_partial2) -// X86-64-LABEL: take_union_hom_fp_partial2(i64, float) -// ARM64-LABEL: take_union_hom_fp_partial2(i64, float) +// X86-64-LABEL: take_union_hom_fp_partial2(float, float, float) +// ARM64-LABEL: take_union_hom_fp_partial2(float, float, float) // At one point, we emitted lifetime.ends without a matching lifetime.start for // CoerceAndExpanded args. Since we're not performing optimizations, neither diff --git a/test/CodeGen/windows-swiftcall.c b/test/CodeGen/windows-swiftcall.c index d8fdec47aa..98fb3bd4b5 100644 --- a/test/CodeGen/windows-swiftcall.c +++ b/test/CodeGen/windows-swiftcall.c @@ -5,7 +5,7 @@ #define ERROR __attribute__((swift_error_result)) #define CONTEXT __attribute__((swift_context)) -// CHECK: [[STRUCT2_RESULT:@.*]] = private {{.*}} constant [[STRUCT2_TYPE:%.*]] { i32 0, i8 0, i8 undef, i8 0, float 0.000000e+00, float 0.000000e+00 } +// CHECK: [[STRUCT2_RESULT:@.*]] = private {{.*}} constant [[STRUCT2_TYPE:%.*]] { i32 0, i8 0, i8 undef, i8 0, i32 0, i32 0 } /*****************************************************************************/ /****************************** PARAMETER ABIS *******************************/ @@ -93,8 +93,8 @@ typedef struct { int x; char c0; char c1; - float f0; - float f1; + int f0; + int f1; } struct_1; TEST(struct_1); // CHECK-LABEL: define dso_local swiftcc { i64, i64 } @return_struct_1() {{.*}}{ @@ -141,8 +141,8 @@ typedef struct { int x; char c0; __attribute__((aligned(2))) char c1; - float f0; - float f1; + int f0; + int f1; } struct_2; TEST(struct_2); // CHECK-LABEL: define dso_local swiftcc { i64, i64 } @return_struct_2() {{.*}}{ @@ -299,20 +299,30 @@ typedef union { TEST(union_hom_fp_partial) // CHECK: define dso_local void @test_union_hom_fp_partial() // CHECK: [[AGG:%.*]] = alloca [[UNION:%.*]], align 16 -// CHECK: [[CALL:%.*]] = call swiftcc { i64, i64 } @return_union_hom_fp_partial() -// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { i64, i64 }* -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 0 -// CHECK: [[T1:%.*]] = extractvalue { i64, i64 } [[CALL]], 0 -// CHECK: store i64 [[T1]], i64* [[T0]], align 16 -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 1 -// CHECK: [[T1:%.*]] = extractvalue { i64, i64 } [[CALL]], 1 -// CHECK: store i64 [[T1]], i64* [[T0]], align 8 -// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { i64, i64 }* -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 0 -// CHECK: [[V0:%.*]] = load i64, i64* [[T0]], align 16 -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 1 -// CHECK: [[V1:%.*]] = load i64, i64* [[T0]], align 8 -// CHECK: call swiftcc void @take_union_hom_fp_partial(i64 [[V0]], i64 [[V1]]) +// CHECK: [[CALL:%.*]] = call swiftcc { float, float, float, float } @return_union_hom_fp_partial() +// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { float, float, float, float }* +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 0 +// CHECK: [[T1:%.*]] = extractvalue { float, float, float, float } [[CALL]], 0 +// CHECK: store float [[T1]], float* [[T0]], align 16 +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 1 +// CHECK: [[T1:%.*]] = extractvalue { float, float, float, float } [[CALL]], 1 +// CHECK: store float [[T1]], float* [[T0]], align 4 +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 2 +// CHECK: [[T1:%.*]] = extractvalue { float, float, float, float } [[CALL]], 2 +// CHECK: store float [[T1]], float* [[T0]], align 8 +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 3 +// CHECK: [[T1:%.*]] = extractvalue { float, float, float, float } [[CALL]], 3 +// CHECK: store float [[T1]], float* [[T0]], align 4 +// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { float, float, float, float }* +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 0 +// CHECK: [[V0:%.*]] = load float, float* [[T0]], align 16 +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 1 +// CHECK: [[V1:%.*]] = load float, float* [[T0]], align 4 +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 2 +// CHECK: [[V2:%.*]] = load float, float* [[T0]], align 8 +// CHECK: [[T0:%.*]] = getelementptr inbounds { float, float, float, float }, { float, float, float, float }* [[CAST]], i32 0, i32 3 +// CHECK: [[V3:%.*]] = load float, float* [[T0]], align 4 +// CHECK: call swiftcc void @take_union_hom_fp_partial(float [[V0]], float [[V1]], float [[V2]], float [[V3]]) // CHECK: ret void // CHECK: } @@ -323,20 +333,25 @@ typedef union { TEST(union_het_fpv_partial) // CHECK-LABEL: define dso_local void @test_union_het_fpv_partial() // CHECK: [[AGG:%.*]] = alloca [[UNION:%.*]], align 16 -// CHECK: [[CALL:%.*]] = call swiftcc { i64, i64 } @return_union_het_fpv_partial() -// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { i64, i64 }* -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 0 -// CHECK: [[T1:%.*]] = extractvalue { i64, i64 } [[CALL]], 0 +// CHECK: [[CALL:%.*]] = call swiftcc { i64, float, float } @return_union_het_fpv_partial() +// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { i64, float, float }* +// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, float, float }, { i64, float, float }* [[CAST]], i32 0, i32 0 +// CHECK: [[T1:%.*]] = extractvalue { i64, float, float } [[CALL]], 0 // CHECK: store i64 [[T1]], i64* [[T0]], align 16 -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 1 -// CHECK: [[T1:%.*]] = extractvalue { i64, i64 } [[CALL]], 1 -// CHECK: store i64 [[T1]], i64* [[T0]], align 8 -// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { i64, i64 }* -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 0 +// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, float, float }, { i64, float, float }* [[CAST]], i32 0, i32 1 +// CHECK: [[T1:%.*]] = extractvalue { i64, float, float } [[CALL]], 1 +// CHECK: store float [[T1]], float* [[T0]], align 8 +// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, float, float }, { i64, float, float }* [[CAST]], i32 0, i32 2 +// CHECK: [[T1:%.*]] = extractvalue { i64, float, float } [[CALL]], 2 +// CHECK: store float [[T1]], float* [[T0]], align 4 +// CHECK: [[CAST:%.*]] = bitcast [[UNION]]* [[AGG]] to { i64, float, float }* +// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, float, float }, { i64, float, float }* [[CAST]], i32 0, i32 0 // CHECK: [[V0:%.*]] = load i64, i64* [[T0]], align 16 -// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[CAST]], i32 0, i32 1 -// CHECK: [[V1:%.*]] = load i64, i64* [[T0]], align 8 -// CHECK: call swiftcc void @take_union_het_fpv_partial(i64 [[V0]], i64 [[V1]]) +// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, float, float }, { i64, float, float }* [[CAST]], i32 0, i32 1 +// CHECK: [[V1:%.*]] = load float, float* [[T0]], align 8 +// CHECK: [[T0:%.*]] = getelementptr inbounds { i64, float, float }, { i64, float, float }* [[CAST]], i32 0, i32 2 +// CHECK: [[V2:%.*]] = load float, float* [[T0]], align 4 +// CHECK: call swiftcc void @take_union_het_fpv_partial(i64 [[V0]], float [[V1]], float [[V2]]) // CHECK: ret void // CHECK: } -- 2.40.0