In swiftcall, don't merge FP/vector types within a chunk.

llvm-svn: 345536
This commit is contained in:
John McCall 2018-10-29 20:32:36 +00:00
parent e3932eeea4
commit d2bfe4b73e
4 changed files with 140 additions and 73 deletions

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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: }