diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp index b17f2f17b25..83934b42e7d 100644 --- a/lib/IRGen/GenStruct.cpp +++ b/lib/IRGen/GenStruct.cpp @@ -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. diff --git a/test/IRGen/c_layout.sil b/test/IRGen/c_layout.sil index 4fc0fa4ecf8..297d861d3d9 100644 --- a/test/IRGen/c_layout.sil +++ b/test/IRGen/c_layout.sil @@ -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]]) diff --git a/test/Reflection/typeref_decoding_imported.swift b/test/Reflection/typeref_decoding_imported.swift index 270fa9133d7..a73b343533b 100644 --- a/test/Reflection/typeref_decoding_imported.swift +++ b/test/Reflection/typeref_decoding_imported.swift @@ -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 diff --git a/test/Reflection/typeref_lowering_imported.swift b/test/Reflection/typeref_lowering_imported.swift index f446d6aa948..e6e84304b10 100644 --- a/test/Reflection/typeref_lowering_imported.swift +++ b/test/Reflection/typeref_lowering_imported.swift @@ -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)))