forked from OSchip/llvm-project
In swiftcall, don't merge FP/vector types within a chunk.
llvm-svn: 345536
This commit is contained in:
parent
e3932eeea4
commit
d2bfe4b73e
|
@ -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
|
||||
|
|
|
@ -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<SomePointer>). 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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: }
|
||||
|
||||
|
|
Loading…
Reference in New Issue