diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h index f3778b1a618..abf3e873957 100644 --- a/include/swift/Runtime/Metadata.h +++ b/include/swift/Runtime/Metadata.h @@ -1038,6 +1038,14 @@ SWIFT_RUNTIME_STDLIB_SPI void _swift_registerConcurrencyStandardTypeDescriptors( const ConcurrencyStandardTypeDescriptors *descriptors); +/// Initialize the value witness table for a struct using the provided like type +/// as the basis for the layout. +SWIFT_RUNTIME_EXPORT +void swift_initRawStructMetadata(StructMetadata *self, + StructLayoutFlags flags, + const TypeLayout *likeType, + size_t count); + #pragma clang diagnostic pop } // end namespace swift diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def index 9c8c083f11f..4bb0512f9bd 100644 --- a/include/swift/Runtime/RuntimeFunctions.def +++ b/include/swift/Runtime/RuntimeFunctions.def @@ -2486,6 +2486,18 @@ FUNCTION(GenericInstantiateLayoutString, ATTRS(NoUnwind), EFFECT(MetaData)) +// void swift_initRawStructMetadata(Metadata *structType, +// StructLayoutFlags flags, +// const TypeLayout *likeType, +// size_t count); +FUNCTION(InitRawStructMetadata, + swift_initRawStructMetadata, + C_CC, AlwaysAvailable, + RETURNS(VoidTy), + ARGS(TypeMetadataPtrTy, SizeTy, Int8PtrPtrTy->getPointerTo(0), SizeTy), + ATTRS(NoUnwind), + EFFECT(MetaData)) + #undef RETURNS #undef ARGS #undef ATTRS diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 1a89f097adc..bf04f35863b 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -134,8 +134,8 @@ AsyncContextLayout::AsyncContextLayout( IRGenModule &IGM, LayoutStrategy strategy, ArrayRef fieldTypes, ArrayRef fieldTypeInfos, CanSILFunctionType originalType, CanSILFunctionType substitutedType, SubstitutionMap substitutionMap) - : StructLayout(IGM, /*decl=*/nullptr, LayoutKind::NonHeapObject, strategy, - fieldTypeInfos, /*typeToFill*/ nullptr), + : StructLayout(IGM, /*type=*/ llvm::None, LayoutKind::NonHeapObject, + strategy, fieldTypeInfos, /*typeToFill*/ nullptr), originalType(originalType), substitutedType(substitutedType), substitutionMap(substitutionMap) { assert(fieldTypeInfos.size() == fieldTypes.size() && diff --git a/lib/IRGen/GenDiffFunc.cpp b/lib/IRGen/GenDiffFunc.cpp index 2bcceb24456..ff6b2151c53 100644 --- a/lib/IRGen/GenDiffFunc.cpp +++ b/lib/IRGen/GenDiffFunc.cpp @@ -211,7 +211,7 @@ public: } StructLayout performLayout(ArrayRef fieldTypes) { - return StructLayout(IGM, /*decl=*/nullptr, LayoutKind::NonHeapObject, + return StructLayout(IGM, /*type=*/ llvm::None, LayoutKind::NonHeapObject, LayoutStrategy::Universal, fieldTypes); } }; @@ -383,7 +383,7 @@ public: } StructLayout performLayout(ArrayRef fieldTypes) { - return StructLayout(IGM, /*decl=*/nullptr, LayoutKind::NonHeapObject, + return StructLayout(IGM, /*type=*/ llvm::None, LayoutKind::NonHeapObject, LayoutStrategy::Universal, fieldTypes); } }; diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp index 099b3914ba0..1ad329871f0 100644 --- a/lib/IRGen/GenHeap.cpp +++ b/lib/IRGen/GenHeap.cpp @@ -274,7 +274,7 @@ HeapLayout::HeapLayout(IRGenModule &IGM, LayoutStrategy strategy, ArrayRef fieldTypeInfos, llvm::StructType *typeToFill, NecessaryBindings &&bindings, unsigned bindingsIndex) - : StructLayout(IGM, /*decl=*/nullptr, LayoutKind::HeapObject, strategy, + : StructLayout(IGM, /*type=*/ llvm::None, LayoutKind::HeapObject, strategy, fieldTypeInfos, typeToFill), ElementTypes(fieldTypes.begin(), fieldTypes.end()), Bindings(std::move(bindings)), BindingsIndex(bindingsIndex) { diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 31c65151b2d..25942f989df 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -2983,6 +2983,20 @@ static void emitInitializeFieldOffsetVectorWithLayoutString( IGM.getPointerSize() * numFields); } +static void emitInitializeRawLayout(IRGenFunction &IGF, SILType likeType, + Size count, SILType T, + llvm::Value *metadata, + MetadataDependencyCollector *collector) { + auto &IGM = IGF.IGM; + auto likeTypeLayout = emitTypeLayoutRef(IGF, likeType, collector); + StructLayoutFlags flags = StructLayoutFlags::Swift5Algorithm; + + // Call swift_initRawStructMetadata(). + IGF.Builder.CreateCall(IGM.getInitRawStructMetadataFunctionPointer(), + {metadata, IGM.getSize(Size(uintptr_t(flags))), + likeTypeLayout, IGM.getSize(count)}); +} + static void emitInitializeValueMetadata(IRGenFunction &IGF, NominalTypeDecl *nominalDecl, llvm::Value *metadata, @@ -2996,10 +3010,34 @@ static void emitInitializeValueMetadata(IRGenFunction &IGF, IGM.getOptions().EnableLayoutStringValueWitnesses && IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation; - if (isa(nominalDecl)) { + if (auto sd = dyn_cast(nominalDecl)) { auto &fixedTI = IGM.getTypeInfo(loweredTy); if (isa(fixedTI)) return; + // Use a different runtime function to initialize the value witness table + // if the struct has a raw layout. The existing swift_initStructMetadata + // is the wrong thing for these types. + if (auto rawLayout = nominalDecl->getAttrs().getAttribute()) { + SILType loweredLikeType; + Size count; + + if (auto likeType = rawLayout->getResolvedScalarLikeType(sd)) { + loweredLikeType = IGM.getLoweredType(AbstractionPattern::getOpaque(), + *likeType); + count = Size(-1); + } else if (auto likeArray = rawLayout->getResolvedArrayLikeTypeAndCount(sd)) { + auto likeType = likeArray->first; + loweredLikeType = IGM.getLoweredType(AbstractionPattern::getOpaque(), + likeType); + + count = Size(likeArray->second); + } + + emitInitializeRawLayout(IGF, loweredLikeType, count, loweredTy, metadata, + collector); + return; + } + if (useLayoutStrings) { emitInitializeFieldOffsetVectorWithLayoutString(IGF, loweredTy, metadata, isVWTMutable, collector); diff --git a/lib/IRGen/GenRecord.h b/lib/IRGen/GenRecord.h index 96dec6d5df4..edb0ec561dc 100644 --- a/lib/IRGen/GenRecord.h +++ b/lib/IRGen/GenRecord.h @@ -863,7 +863,6 @@ public: fields.reserve(astFields.size()); fieldTypesForLayout.reserve(astFields.size()); - bool loadable = true; auto fieldsABIAccessible = FieldsAreABIAccessible; unsigned explosionSize = 0; @@ -880,7 +879,6 @@ public: auto loadableFieldTI = dyn_cast(&fieldTI); if (!loadableFieldTI) { - loadable = false; continue; } @@ -902,7 +900,7 @@ public: } // Create the type info. - if (loadable) { + if (layout.isLoadable()) { assert(layout.isFixedLayout()); assert(fieldsABIAccessible); return asImpl()->createLoadable(fields, std::move(layout), explosionSize); diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp index e4d96c81aaa..ce495981a5f 100644 --- a/lib/IRGen/GenStruct.cpp +++ b/lib/IRGen/GenStruct.cpp @@ -1088,6 +1088,35 @@ namespace { fields.push_back( field.getTypeInfo().buildTypeLayoutEntry(IGM, fieldTy, useStructLayouts)); } + + auto decl = T.getASTType()->getStructOrBoundGenericStruct(); + auto rawLayout = decl->getAttrs().getAttribute(); + + // If we have a raw layout struct who is non-fixed size, it means the + // layout of the struct is dependent on the archetype of the thing it's + // like. + if (rawLayout) { + SILType loweredLikeType; + + if (auto likeType = rawLayout->getResolvedScalarLikeType(decl)) { + loweredLikeType = IGM.getLoweredType(*likeType); + } else if (auto likeArray = rawLayout->getResolvedArrayLikeTypeAndCount(decl)) { + loweredLikeType = IGM.getLoweredType(likeArray->first); + } + + // The given struct type T that we're building may be in a generic + // environment that is different than that which was built our + // resolved rawLayout like type. Map our like type into the given + // environment. + auto subs = T.getASTType()->getContextSubstitutionMap( + IGM.getSwiftModule(), decl); + + loweredLikeType = loweredLikeType.subst(IGM.getSILModule(), subs); + + return IGM.getTypeInfo(loweredLikeType).buildTypeLayoutEntry(IGM, + loweredLikeType, useStructLayouts); + } + assert(!fields.empty() && "Empty structs should not be NonFixedStructTypeInfo"); @@ -1244,8 +1273,7 @@ namespace { } StructLayout performLayout(ArrayRef fieldTypes) { - return StructLayout(IGM, TheStruct->getAnyNominal(), - LayoutKind::NonHeapObject, + return StructLayout(IGM, TheStruct, LayoutKind::NonHeapObject, LayoutStrategy::Optimal, fieldTypes, StructTy); } }; diff --git a/lib/IRGen/GenTuple.cpp b/lib/IRGen/GenTuple.cpp index f276c4fdb6f..d565ac53949 100644 --- a/lib/IRGen/GenTuple.cpp +++ b/lib/IRGen/GenTuple.cpp @@ -512,7 +512,7 @@ namespace { } StructLayout performLayout(ArrayRef fieldTypes) { - return StructLayout(IGM, /*decl=*/nullptr, LayoutKind::NonHeapObject, + return StructLayout(IGM, /*type=*/ llvm::None, LayoutKind::NonHeapObject, LayoutStrategy::Universal, fieldTypes); } }; diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp index ab1c37a0022..8f2463258c2 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -2437,6 +2437,17 @@ namespace { if (IGM.isResilient(decl, ResilienceExpansion::Maximal)) return true; + auto rawLayout = decl->getAttrs().getAttribute(); + + // If our struct has a raw layout, it may be dependent on the like type. + if (rawLayout) { + if (auto likeType = rawLayout->getResolvedScalarLikeType(decl)) { + return visit((*likeType)->getCanonicalType()); + } else if (auto likeArray = rawLayout->getResolvedArrayLikeTypeAndCount(decl)) { + return visit(likeArray->first->getCanonicalType()); + } + } + for (auto field : decl->getStoredProperties()) { if (visit(field->getInterfaceType()->getCanonicalType())) return true; diff --git a/lib/IRGen/StructLayout.cpp b/lib/IRGen/StructLayout.cpp index 25f5815d7b3..6b918fc5cf0 100644 --- a/lib/IRGen/StructLayout.cpp +++ b/lib/IRGen/StructLayout.cpp @@ -43,11 +43,17 @@ static bool requiresHeapHeader(LayoutKind kind) { /// Perform structure layout on the given types. StructLayout::StructLayout(IRGenModule &IGM, - NominalTypeDecl *decl, + llvm::Optional type, LayoutKind layoutKind, LayoutStrategy strategy, ArrayRef types, llvm::StructType *typeToFill) { + NominalTypeDecl *decl = nullptr; + + if (type) { + decl = type->getAnyNominal(); + } + Elements.reserve(types.size()); // Fill in the Elements array. @@ -73,7 +79,7 @@ StructLayout::StructLayout(IRGenModule &IGM, if (decl) { rawLayout = decl->getAttrs().getAttribute(); } - if (rawLayout) { + if (rawLayout && type) { auto sd = cast(decl); IsKnownTriviallyDestroyable = deinit; IsKnownBitwiseTakable = IsBitwiseTakable; @@ -82,6 +88,7 @@ StructLayout::StructLayout(IRGenModule &IGM, IsKnownCopyable = copyable; assert(builder.getHeaderSize() == Size(0)); headerSize = Size(0); + IsLoadable = false; auto &Diags = IGM.Context.Diags; // Fixed size and alignment specified. @@ -100,9 +107,12 @@ StructLayout::StructLayout(IRGenModule &IGM, IsFixedLayout = true; IsKnownAlwaysFixedSize = IsFixedSize; } else if (auto likeType = rawLayout->getResolvedScalarLikeType(sd)) { - const TypeInfo &likeTypeInfo - = IGM.getTypeInfoForUnlowered(AbstractionPattern::getOpaque(), - *likeType); + // If our likeType is dependent, then all calls to try and lay it out will + // be non-fixed, but in a concrete case we want a fixed layout, so try to + // substitute it out. + auto subs = (*type)->getContextSubstitutionMap(IGM.getSwiftModule(), decl); + auto loweredLikeType = IGM.getLoweredType(likeType->subst(subs)); + const TypeInfo &likeTypeInfo = IGM.getTypeInfo(loweredLikeType); // Take layout attributes from the like type. if (const FixedTypeInfo *likeFixedType = dyn_cast(&likeTypeInfo)) { @@ -121,9 +131,9 @@ StructLayout::StructLayout(IRGenModule &IGM, auto elementType = likeArray->first; unsigned count = likeArray->second; - const TypeInfo &likeTypeInfo - = IGM.getTypeInfoForUnlowered(AbstractionPattern::getOpaque(), - elementType); + auto subs = (*type)->getContextSubstitutionMap(IGM.getSwiftModule(), decl); + auto loweredElementType = IGM.getLoweredType(elementType.subst(subs)); + const TypeInfo &likeTypeInfo = IGM.getTypeInfo(loweredElementType); // Take layout attributes from the like type. if (const FixedTypeInfo *likeFixedType = dyn_cast(&likeTypeInfo)) { @@ -155,11 +165,6 @@ StructLayout::StructLayout(IRGenModule &IGM, } } else { Ty = (typeToFill ? typeToFill : IGM.OpaqueTy); - - // TODO: For types with dependent layout, the metadata initialization also - // has to be updated to account for the raw layout description. - Diags.diagnose(rawLayout->getLocation(), - diag::raw_layout_dynamic_type_layout_unsupported); } } else { bool nonEmpty = builder.addFields(Elements, strategy); @@ -174,6 +179,7 @@ StructLayout::StructLayout(IRGenModule &IGM, headerSize = builder.getHeaderSize(); SpareBits.clear(); IsFixedLayout = true; + IsLoadable = true; IsKnownTriviallyDestroyable = deinit; IsKnownBitwiseTakable = IsBitwiseTakable; IsKnownAlwaysFixedSize = IsFixedSize; @@ -185,6 +191,7 @@ StructLayout::StructLayout(IRGenModule &IGM, headerSize = builder.getHeaderSize(); SpareBits = builder.getSpareBits(); IsFixedLayout = builder.isFixedLayout(); + IsLoadable = builder.isLoadable(); IsKnownTriviallyDestroyable = deinit & builder.isTriviallyDestroyable(); IsKnownBitwiseTakable = builder.isBitwiseTakable(); IsKnownAlwaysFixedSize = builder.isAlwaysFixedSize(); @@ -379,6 +386,7 @@ bool StructLayoutBuilder::addField(ElementLayout &elt, IsKnownTriviallyDestroyable &= eltTI.isTriviallyDestroyable(ResilienceExpansion::Maximal); IsKnownBitwiseTakable &= eltTI.isBitwiseTakable(ResilienceExpansion::Maximal); IsKnownAlwaysFixedSize &= eltTI.isFixedSize(ResilienceExpansion::Minimal); + IsLoadable &= eltTI.isLoadable(); if (eltTI.isKnownEmpty(ResilienceExpansion::Maximal)) { addEmptyElement(elt); diff --git a/lib/IRGen/StructLayout.h b/lib/IRGen/StructLayout.h index 7b18823bc0a..68057acb6e0 100644 --- a/lib/IRGen/StructLayout.h +++ b/lib/IRGen/StructLayout.h @@ -283,6 +283,7 @@ private: SmallVector CurSpareBits; unsigned NextNonFixedOffsetIndex = 0; bool IsFixedLayout = true; + bool IsLoadable = true; IsTriviallyDestroyable_t IsKnownTriviallyDestroyable = IsTriviallyDestroyable; IsBitwiseTakable_t IsKnownBitwiseTakable = IsBitwiseTakable; IsCopyable_t IsKnownCopyable = IsCopyable; @@ -327,6 +328,9 @@ public: /// Return whether the structure has a fixed-size layout. bool isFixedLayout() const { return IsFixedLayout; } + /// Return whether the structure has a loadable layout. + bool isLoadable() const { return IsLoadable; } + /// Return whether the structure is known to be POD in the local /// resilience scope. IsTriviallyDestroyable_t isTriviallyDestroyable() const { return IsKnownTriviallyDestroyable; } @@ -402,6 +406,9 @@ class StructLayout { /// alignment are exact. bool IsFixedLayout; + /// Whether this layout + bool IsLoadable; + IsTriviallyDestroyable_t IsKnownTriviallyDestroyable; IsBitwiseTakable_t IsKnownBitwiseTakable; IsCopyable_t IsKnownCopyable; @@ -419,7 +426,7 @@ public: /// layout must include the reference-counting header /// \param typeToFill - if present, must be an opaque type whose body /// will be filled with this layout - StructLayout(IRGenModule &IGM, NominalTypeDecl *decl, + StructLayout(IRGenModule &IGM, llvm::Optional type, LayoutKind kind, LayoutStrategy strategy, ArrayRef fields, llvm::StructType *typeToFill = 0); @@ -434,6 +441,7 @@ public: headerSize(builder.getHeaderSize()), SpareBits(builder.getSpareBits()), IsFixedLayout(builder.isFixedLayout()), + IsLoadable(builder.isLoadable()), IsKnownTriviallyDestroyable(builder.isTriviallyDestroyable()), IsKnownBitwiseTakable(builder.isBitwiseTakable()), IsKnownCopyable(builder.isCopyable()), @@ -467,6 +475,7 @@ public: } bool isFixedLayout() const { return IsFixedLayout; } + bool isLoadable() const { return IsLoadable; } llvm::Constant *emitSize(IRGenModule &IGM) const; llvm::Constant *emitAlignMask(IRGenModule &IGM) const; diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index e308cae2ee0..d30bde5d503 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -2905,6 +2905,35 @@ metadata: } } +/// Initialize the value witness table for a @_rawLayout struct. +SWIFT_RUNTIME_EXPORT +void swift::swift_initRawStructMetadata(StructMetadata *structType, + StructLayoutFlags layoutFlags, + const TypeLayout *likeTypeLayout, + size_t count) { + auto vwtable = getMutableVWTableForInit(structType, layoutFlags); + + // The existing vwt function entries are all fine to preserve, the only thing + // we need to initialize is the actual type layout. + auto size = likeTypeLayout->size; + auto stride = likeTypeLayout->stride; + auto alignMask = likeTypeLayout->flags.getAlignmentMask(); + auto extraInhabitantCount = likeTypeLayout->extraInhabitantCount; + + // If our count is greater than or equal 0, we're dealing an array like layout. + if (count >= 0) { + stride *= count; + size = stride; + } + + vwtable->size = size; + vwtable->stride = stride; + vwtable->flags = ValueWitnessFlags() + .withAlignmentMask(alignMask) + .withCopyable(false); + vwtable->extraInhabitantCount = extraInhabitantCount; +} + /***************************************************************************/ /*** Classes ***************************************************************/ /***************************************************************************/ diff --git a/test/IRGen/raw_layout.swift b/test/IRGen/raw_layout.swift index 95528c727d8..1d59d4c1bdb 100644 --- a/test/IRGen/raw_layout.swift +++ b/test/IRGen/raw_layout.swift @@ -64,18 +64,75 @@ struct Keymaster: ~Copyable { let lock3: Lock } -/* -TODO: Dependent layout not yet implemented +// Dependent Layouts: +// These types have their layouts all zeroed out and will be fixed up at +// runtime. +// CHECK-LABEL: @"$s{{[A-Za-z0-9_]*}}4CellVWV" = {{.*}} %swift.vwtable +// size +// CHECK-SAME: , {{i64|i32}} 0 +// stride +// CHECK-SAME: , {{i64|i32}} 0 +// flags: alignment 0, incomplete +// CHECK-SAME: , @_rawLayout(like: T) struct Cell: ~Copyable {} +// CHECK-LABEL: @"$s{{[A-Za-z0-9_]*}}10PaddedCellVWV" = {{.*}} %swift.vwtable +// size +// CHECK-SAME: , {{i64|i32}} 0 +// stride +// CHECK-SAME: , {{i64|i32}} 0 +// flags: alignment 0, incomplete +// CHECK-SAME: , @_rawLayout(likeArrayOf: T, count: 1) struct PaddedCell: ~Copyable {} +// CHECK-LABEL: @"$s{{[A-Za-z0-9_]*}}14SmallVectorBufVWV" = {{.*}} %swift.vwtable +// size +// CHECK-SAME: , {{i64|i32}} 0 +// stride +// CHECK-SAME: , {{i64|i32}} 0 +// flags: alignment 0, incomplete +// CHECK-SAME: , @_rawLayout(likeArrayOf: T, count: 8) struct SmallVectorBuf: ~Copyable {} -*/ + +// CHECK-LABEL: @"$s{{[A-Za-z0-9_]*}}8UsesCellVWV" = {{.*}} %swift.vwtable +// size +// CHECK-SAME: , {{i64|i32}} 8 +// stride +// CHECK-SAME: , {{i64|i32}} 8 +// flags: alignment 3, noncopyable +// CHECK-SAME: , +struct UsesCell: ~Copyable { + let someCondition: Bool + let specialInt: Cell +} + +// Dependent layout metadata initialization: + +// Cell + +// CHECK-LABEL: define {{.*}} swiftcc %swift.metadata_response @"$s{{[A-Za-z0-9_]*}}4CellVMr"(ptr %"Cell", ptr {{.*}}, ptr {{.*}}) +// CHECK: [[T_ADDR:%.*]] = getelementptr inbounds ptr, ptr %"Cell", {{i64|i32}} 2 +// CHECK-NEXT: [[T:%.*]] = load ptr, ptr [[T_ADDR]] +// CHECK-NEXT: [[RESPONSE:%.*]] = call swiftcc %swift.metadata_response @swift_checkMetadataState({{i64|i32}} 319, ptr [[T]]) +// CHECK-NEXT: [[T:%.*]] = extractvalue %swift.metadata_response [[RESPONSE]], 0 +// CHECK: [[T_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[T]], {{i64|i32}} -1 +// CHECK-NEXT: [[T_VWT:%.*]] = load ptr, ptr [[T_VWT_ADDR]] +// CHECK-NEXT: [[T_LAYOUT:%.*]] = getelementptr inbounds ptr, ptr [[T_VWT]], i32 8 +// CHECK-NEXT: call void @swift_initRawStructMetadata(ptr %"Cell", {{i64|i32}} 0, ptr [[T_LAYOUT]], {{i64|i32}} -1) + +// PaddedCell + +// CHECK-LABEL: define {{.*}} swiftcc %swift.metadata_response @"$s{{[A-Za-z0-9_]*}}10PaddedCellVMr"(ptr %"PaddedCell", ptr {{.*}}, ptr {{.*}}) +// CHECK: call void @swift_initRawStructMetadata(ptr %"PaddedCell", {{i64|i32}} 0, ptr {{%.*}}, {{i64|i32}} 1) + +// SmallVectorBuf + +// CHECK-LABEL: define {{.*}} swiftcc %swift.metadata_response @"$s{{[A-Za-z0-9_]*}}14SmallVectorBufVMr"(ptr %"SmallVectorBuf", ptr {{.*}}, ptr {{.*}}) +// CHECK: call void @swift_initRawStructMetadata(ptr %"SmallVectorBuf", {{i64|i32}} 0, ptr {{%.*}}, {{i64|i32}} 8) sil @use_lock : $@convention(thin) (@in_guaranteed Lock) -> () { entry(%L: $*Lock): diff --git a/test/Interpreter/raw_layout.swift b/test/Interpreter/raw_layout.swift new file mode 100644 index 00000000000..f4766fabd6d --- /dev/null +++ b/test/Interpreter/raw_layout.swift @@ -0,0 +1,71 @@ +// RUN: %target-run-simple-swift(-enable-experimental-feature RawLayout -enable-builtin-module) | %FileCheck %s +// REQUIRES: executable_test + +import Builtin + +@_rawLayout(like: T) +struct Cell: ~Copyable { + var address: UnsafeMutablePointer { + UnsafeMutablePointer(Builtin.unprotectedAddressOfBorrow(self)) + } + + init(_ value: consuming T) { + address.initialize(to: value) + } + + deinit { + address.deinitialize(count: 1) + + // Note: We don't need to deallocate the address here because the memory it + // points to is being destroyed within this deinit. + } + + borrowing func replace(with replacement: consuming T) -> T { + let previous = address.move() + address.initialize(to: replacement) + return previous + } + + borrowing func set(_ value: consuming T) { + let previous = replace(with: value) + _ = consume previous + } + + consuming func get() -> T { + // Move the value out of self and don't call our deinitializer + let previous = address.move() + discard self + return previous + } +} + +@_eagerMove +class SpecialInt { + var value: Int + + init(_ value: Int) { + self.value = value + } + + deinit { + print("Deinitializing \(value)!") + } +} + +do { + let specialInt0 = SpecialInt(128) + let cell0 = Cell(specialInt0) + + let specialInt0Again = cell0.replace(with: SpecialInt(316)) + + // CHECK: Deinitializing 128! + _ = consume specialInt0Again + + // CHECK: Deinitializing 316! + cell0.set(SpecialInt(592)) + + let specialInt1 = cell0.get() + + // CHECK: Deinitializing 592! + _ = consume specialInt1 +} diff --git a/test/Sema/raw_layout.swift b/test/Sema/raw_layout.swift index 7cd4f463626..fb1cdf0f538 100644 --- a/test/Sema/raw_layout.swift +++ b/test/Sema/raw_layout.swift @@ -45,4 +45,3 @@ struct Butt { @_rawLayout(size: 4, alignment: 4) @_alignment(16) // expected-error{{type with @_rawLayout cannot also have an @_alignment attribute}} struct RawLayoutAndAlignment: ~Copyable {} -