Count tail-padding in the size of imported C types.

This allows us to freely pass the address of a variable of such
types to a C function without worrying about it overwriting other
things if e.g. it memcpy's sizeof(T) bytes and thus clobbers the
otherwise-non-existent tail padding.

There are ways to get this optimization back, but they require
things like materializing to a temporary instead of passing the
address directly.  We haven't done that work yet, so we don't
get to take advantage of it.

rdar://26828018
This commit is contained in:
John McCall
2016-08-02 13:26:11 -07:00
parent 212ffadf5e
commit b51a69f29f
4 changed files with 33 additions and 34 deletions

View File

@@ -579,7 +579,6 @@ class ClangRecordLowering {
const clang::ASTContext &ClangContext;
const clang::ASTRecordLayout &ClangLayout;
const Size TotalStride;
Size TotalSize;
const Alignment TotalAlignment;
SpareBitVector SpareBits;
@@ -595,9 +594,8 @@ public:
ClangDecl(clangDecl), ClangContext(clangDecl->getASTContext()),
ClangLayout(ClangContext.getASTRecordLayout(clangDecl)),
TotalStride(Size(ClangLayout.getSize().getQuantity())),
TotalSize(TotalStride),
TotalAlignment(Alignment(ClangLayout.getAlignment().getQuantity())) {
SpareBits.reserve(TotalSize.getValue() * 8);
SpareBits.reserve(TotalStride.getValue() * 8);
}
void collectRecordFields() {
@@ -606,17 +604,12 @@ public:
} else {
collectStructFields();
}
// Lots of layout will get screwed up if our structure claims more
// storage than we allocated to it.
assert(NextOffset == TotalSize && NextOffset <= TotalStride);
assert(TotalSize.roundUpToAlignment(TotalAlignment) == TotalStride);
}
const TypeInfo *createTypeInfo(llvm::StructType *llvmType) {
llvmType->setBody(LLVMFields, /*packed*/ true);
return ClangRecordTypeInfo::create(FieldInfos, NextExplosionIndex,
llvmType, TotalSize,
llvmType, TotalStride,
std::move(SpareBits), TotalAlignment,
ClangDecl);
}
@@ -624,7 +617,7 @@ public:
private:
/// Collect all the fields of a union.
void collectUnionFields() {
addOpaqueField(Size(0), TotalSize);
addOpaqueField(Size(0), TotalStride);
}
static bool isImportOfClangField(VarDecl *swiftField,
@@ -689,8 +682,14 @@ private:
assert(sfi == sfe && "more Swift fields than there were Clang fields?");
// Treat this as the end of the value size.
TotalSize = NextOffset;
// We never take advantage of tail padding, because that would prevent
// us from passing the address of the object off to C, which is a pretty
// likely scenario for imported C types.
assert(NextOffset <= TotalStride);
assert(SpareBits.size() <= TotalStride.getValueInBits());
if (NextOffset < TotalStride) {
addPaddingField(TotalStride);
}
}
/// Place the next struct field at its appropriate offset.

View File

@@ -7,8 +7,8 @@ import Swift
// TODO: Provide tests for other architectures
// CHECK-x86_64: %VSC11BitfieldOne = type <{ %Vs6UInt32, %VSC6Nested, [1 x i8], [4 x i8], [4 x i8], %Sf, [1 x i8], [7 x i8], %Vs6UInt64, %Vs6UInt32 }>
// CHECK-x86_64: %VSC6Nested = type <{ %Sf, [3 x i8] }>
// CHECK-x86_64: %VSC11BitfieldOne = type <{ %Vs6UInt32, %VSC6Nested, [4 x i8], [4 x i8], %Sf, [1 x i8], [7 x i8], %Vs6UInt64, %Vs6UInt32, [4 x i8] }>
// CHECK-x86_64: %VSC6Nested = type <{ %Sf, [3 x i8], [1 x i8] }>
// CHECK-x86_64: %VSC26BitfieldSeparatorReference = type [[BITFIELD_SEP_TYPE:<{ %Vs5UInt8, \[3 x i8\], %Vs5UInt8 }>]]
// CHECK-x86_64: %VSC25BitfieldSeparatorSameName = type [[BITFIELD_SEP_TYPE]]
@@ -42,22 +42,22 @@ bb0:
// CHECK-x86_64: [[ADDR_B_YZ:%.*]] = getelementptr inbounds %VSC6Nested, %VSC6Nested* [[ADDR_B]], i32 0, i32 1
// CHECK-x86_64: [[ADDR_B_YZ_1:%.*]] = bitcast [3 x i8]* [[ADDR_B_YZ]] to i24*
// CHECK-x86_64: [[B_YZ:%.*]] = load i24, i24* [[ADDR_B_YZ_1]], align 4
// CHECK-x86_64: [[ADDR_CDE:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[RESULT]], i32 0, i32 3
// CHECK-x86_64: [[ADDR_CDE:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[RESULT]], i32 0, i32 2
// CHECK-x86_64: [[ADDR_CDE_1:%.*]] = bitcast [4 x i8]* [[ADDR_CDE]] to i32*
// CHECK-x86_64: [[CDE:%.*]] = load i32, i32* [[ADDR_CDE_1]], align 4
// CHECK-x86_64: [[ADDR_FGH:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[RESULT]], i32 0, i32 4
// CHECK-x86_64: [[ADDR_FGH:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[RESULT]], i32 0, i32 3
// CHECK-x86_64: [[ADDR_FGH_1:%.*]] = bitcast [4 x i8]* [[ADDR_FGH]] to i32*
// CHECK-x86_64: [[FGH:%.*]] = load i32, i32* [[ADDR_FGH_1]], align 8
// CHECK-x86_64: [[ADDR_I:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[RESULT]], i32 0, i32 5
// CHECK-x86_64: [[ADDR_I:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[RESULT]], i32 0, i32 4
// CHECK-x86_64: [[ADDR_I_V:%.*]] = getelementptr inbounds %Sf, %Sf* [[ADDR_I]], i32 0, i32 0
// CHECK-x86_64: [[I:%.*]] = load float, float* [[ADDR_I_V]], align 4
// CHECK-x86_64: [[ADDR_JK:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[RESULT]], i32 0, i32 6
// CHECK-x86_64: [[ADDR_JK:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[RESULT]], i32 0, i32 5
// CHECK-x86_64: [[ADDR_JK_1:%.*]] = bitcast [1 x i8]* [[ADDR_JK]] to i8*
// CHECK-x86_64: [[JK:%.*]] = load i8, i8* [[ADDR_JK_1]], align 8
// CHECK-x86_64: [[ADDR_L:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[RESULT]], i32 0, i32 8
// CHECK-x86_64: [[ADDR_L:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[RESULT]], i32 0, i32 7
// CHECK-x86_64: [[ADDR_L_V:%.*]] = getelementptr inbounds %Vs6UInt64, %Vs6UInt64* [[ADDR_L]], i32 0, i32 0
// CHECK-x86_64: [[L:%.*]] = load i64, i64* [[ADDR_L_V]], align 8
// CHECK-x86_64: [[ADDR_M:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[RESULT]], i32 0, i32 9
// CHECK-x86_64: [[ADDR_M:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[RESULT]], i32 0, i32 8
// CHECK-x86_64: [[ADDR_M_V:%.*]] = getelementptr inbounds %Vs6UInt32, %Vs6UInt32* [[ADDR_M]], i32 0, i32 0
// CHECK-x86_64: [[M:%.*]] = load i32, i32* [[ADDR_M_V]], align 8
// Put all of the values into the indirect argument and make the second call.
@@ -71,22 +71,22 @@ bb0:
// CHECK-x86_64: [[ADDR_B_YZ:%.*]] = getelementptr inbounds %VSC6Nested, %VSC6Nested* [[ADDR_B]], i32 0, i32 1
// CHECK-x86_64: [[ADDR_B_YZ_1:%.*]] = bitcast [3 x i8]* [[ADDR_B_YZ]] to i24*
// CHECK-x86_64: store i24 [[B_YZ]], i24* [[ADDR_B_YZ_1]], align 4
// CHECK-x86_64: [[ADDR_CDE:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[ARG]], i32 0, i32 3
// CHECK-x86_64: [[ADDR_CDE:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[ARG]], i32 0, i32 2
// CHECK-x86_64: [[ADDR_CDE_1:%.*]] = bitcast [4 x i8]* [[ADDR_CDE]] to i32*
// CHECK-x86_64: store i32 [[CDE]], i32* [[ADDR_CDE_1]], align 4
// CHECK-x86_64: [[ADDR_FGH:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[ARG]], i32 0, i32 4
// CHECK-x86_64: [[ADDR_FGH:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[ARG]], i32 0, i32 3
// CHECK-x86_64: [[ADDR_FGH_1:%.*]] = bitcast [4 x i8]* [[ADDR_FGH]] to i32*
// CHECK-x86_64: store i32 [[FGH]], i32* [[ADDR_FGH_1]], align 8
// CHECK-x86_64: [[ADDR_I:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[ARG]], i32 0, i32 5
// CHECK-x86_64: [[ADDR_I:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[ARG]], i32 0, i32 4
// CHECK-x86_64: [[ADDR_I_V:%.*]] = getelementptr inbounds %Sf, %Sf* [[ADDR_I]], i32 0, i32 0
// CHECK-x86_64: store float [[I]], float* [[ADDR_I_V]], align 4
// CHECK-x86_64: [[ADDR_JK:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[ARG]], i32 0, i32 6
// CHECK-x86_64: [[ADDR_JK:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[ARG]], i32 0, i32 5
// CHECK-x86_64: [[ADDR_JK_1:%.*]] = bitcast [1 x i8]* [[ADDR_JK]] to i8*
// CHECK-x86_64: store i8 [[JK]], i8* [[ADDR_JK_1]], align 8
// CHECK-x86_64: [[ADDR_L:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[ARG]], i32 0, i32 8
// CHECK-x86_64: [[ADDR_L:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[ARG]], i32 0, i32 7
// CHECK-x86_64: [[ADDR_L_V:%.*]] = getelementptr inbounds %Vs6UInt64, %Vs6UInt64* [[ADDR_L]], i32 0, i32 0
// CHECK-x86_64: store i64 [[L]], i64* [[ADDR_L_V]], align 8
// CHECK-x86_64: [[ADDR_M:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[ARG]], i32 0, i32 9
// CHECK-x86_64: [[ADDR_M:%.*]] = getelementptr inbounds %VSC11BitfieldOne, %VSC11BitfieldOne* [[ARG]], i32 0, i32 8
// CHECK-x86_64: [[ADDR_M_V:%.*]] = getelementptr inbounds %Vs6UInt32, %Vs6UInt32* [[ADDR_M]], i32 0, i32 0
// CHECK-x86_64: store i32 [[M]], i32* [[ADDR_M_V]], align 8
// CHECK-x86_64: call void @consumeBitfieldOne(%VSC11BitfieldOne* byval align 8 [[ARG]])

View File

@@ -81,7 +81,7 @@
// CHECK-64: ==============
// CHECK-64: - __C.MyCStruct:
// CHECK-64: Size: 17
// CHECK-64: Size: 24
// CHECK-64: Alignment: 8
// CHECK-64: Stride: 24
// CHECK-64: NumExtraInhabitants: 0
@@ -99,7 +99,7 @@
// CHECK-64: NumExtraInhabitants: 0
// CHECK-64: - __C.MyCStructWithBitfields:
// CHECK-64: Size: 2
// CHECK-64: Size: 4
// CHECK-64: Alignment: 4
// CHECK-64: Stride: 4
// CHECK-64: NumExtraInhabitants: 0

View File

@@ -7,13 +7,13 @@
V12TypeLowering9HasCTypes
// CHECK: (struct TypeLowering.HasCTypes)
// CHECK-NEXT: (struct size=34 alignment=8 stride=40 num_extra_inhabitants=0
// CHECK-NEXT: (struct size=44 alignment=8 stride=48 num_extra_inhabitants=0
// CHECK-NEXT: (field name=mcs offset=0
// CHECK-NEXT: (builtin size=17 alignment=8 stride=24 num_extra_inhabitants=0))
// CHECK-NEXT: (field name=mce offset=20
// CHECK-NEXT: (builtin size=24 alignment=8 stride=24 num_extra_inhabitants=0))
// CHECK-NEXT: (field name=mce offset=24
// CHECK-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0))
// CHECK-NEXT: (field name=mcu offset=24
// CHECK-NEXT: (field name=mcu offset=32
// CHECK-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0))
// CHECK-NEXT: (field name=mcsbf offset=32
// CHECK-NEXT: (builtin size=2 alignment=4 stride=4 num_extra_inhabitants=0)))
// CHECK-NEXT: (field name=mcsbf offset=40
// CHECK-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))