Skip to content

Commit c7dd5c7

Browse files
committed
Implement dependent layouts for raw types
Update raw_layout.swift Allow for concrete specializations of raw layout
1 parent a22bd27 commit c7dd5c7

File tree

16 files changed

+298
-30
lines changed

16 files changed

+298
-30
lines changed

include/swift/Runtime/Metadata.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,14 @@ SWIFT_RUNTIME_STDLIB_SPI
10381038
void _swift_registerConcurrencyStandardTypeDescriptors(
10391039
const ConcurrencyStandardTypeDescriptors *descriptors);
10401040

1041+
/// Initialize the value witness table for a struct using the provided like type
1042+
/// as the basis for the layout.
1043+
SWIFT_RUNTIME_EXPORT
1044+
void swift_initRawStructMetadata(StructMetadata *self,
1045+
StructLayoutFlags flags,
1046+
const TypeLayout *likeType,
1047+
size_t count);
1048+
10411049
#pragma clang diagnostic pop
10421050

10431051
} // end namespace swift

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2486,6 +2486,18 @@ FUNCTION(GenericInstantiateLayoutString,
24862486
ATTRS(NoUnwind),
24872487
EFFECT(MetaData))
24882488

2489+
// void swift_initRawStructMetadata(Metadata *structType,
2490+
// StructLayoutFlags flags,
2491+
// const TypeLayout *likeType,
2492+
// size_t count);
2493+
FUNCTION(InitRawStructMetadata,
2494+
swift_initRawStructMetadata,
2495+
C_CC, AlwaysAvailable,
2496+
RETURNS(VoidTy),
2497+
ARGS(TypeMetadataPtrTy, SizeTy, Int8PtrPtrTy->getPointerTo(0), SizeTy),
2498+
ATTRS(NoUnwind),
2499+
EFFECT(MetaData))
2500+
24892501
#undef RETURNS
24902502
#undef ARGS
24912503
#undef ATTRS

lib/IRGen/GenCall.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ AsyncContextLayout::AsyncContextLayout(
134134
IRGenModule &IGM, LayoutStrategy strategy, ArrayRef<SILType> fieldTypes,
135135
ArrayRef<const TypeInfo *> fieldTypeInfos, CanSILFunctionType originalType,
136136
CanSILFunctionType substitutedType, SubstitutionMap substitutionMap)
137-
: StructLayout(IGM, /*decl=*/nullptr, LayoutKind::NonHeapObject, strategy,
138-
fieldTypeInfos, /*typeToFill*/ nullptr),
137+
: StructLayout(IGM, /*type=*/ llvm::None, LayoutKind::NonHeapObject,
138+
strategy, fieldTypeInfos, /*typeToFill*/ nullptr),
139139
originalType(originalType), substitutedType(substitutedType),
140140
substitutionMap(substitutionMap) {
141141
assert(fieldTypeInfos.size() == fieldTypes.size() &&

lib/IRGen/GenDiffFunc.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ class DifferentiableFuncTypeBuilder
211211
}
212212

213213
StructLayout performLayout(ArrayRef<const TypeInfo *> fieldTypes) {
214-
return StructLayout(IGM, /*decl=*/nullptr, LayoutKind::NonHeapObject,
214+
return StructLayout(IGM, /*type=*/ llvm::None, LayoutKind::NonHeapObject,
215215
LayoutStrategy::Universal, fieldTypes);
216216
}
217217
};
@@ -383,7 +383,7 @@ class LinearFuncTypeBuilder
383383
}
384384

385385
StructLayout performLayout(ArrayRef<const TypeInfo *> fieldTypes) {
386-
return StructLayout(IGM, /*decl=*/nullptr, LayoutKind::NonHeapObject,
386+
return StructLayout(IGM, /*type=*/ llvm::None, LayoutKind::NonHeapObject,
387387
LayoutStrategy::Universal, fieldTypes);
388388
}
389389
};

lib/IRGen/GenHeap.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ HeapLayout::HeapLayout(IRGenModule &IGM, LayoutStrategy strategy,
274274
ArrayRef<const TypeInfo *> fieldTypeInfos,
275275
llvm::StructType *typeToFill,
276276
NecessaryBindings &&bindings, unsigned bindingsIndex)
277-
: StructLayout(IGM, /*decl=*/nullptr, LayoutKind::HeapObject, strategy,
277+
: StructLayout(IGM, /*type=*/ llvm::None, LayoutKind::HeapObject, strategy,
278278
fieldTypeInfos, typeToFill),
279279
ElementTypes(fieldTypes.begin(), fieldTypes.end()),
280280
Bindings(std::move(bindings)), BindingsIndex(bindingsIndex) {

lib/IRGen/GenMeta.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2983,6 +2983,20 @@ static void emitInitializeFieldOffsetVectorWithLayoutString(
29832983
IGM.getPointerSize() * numFields);
29842984
}
29852985

2986+
static void emitInitializeRawLayout(IRGenFunction &IGF, SILType likeType,
2987+
Size count, SILType T,
2988+
llvm::Value *metadata,
2989+
MetadataDependencyCollector *collector) {
2990+
auto &IGM = IGF.IGM;
2991+
auto likeTypeLayout = emitTypeLayoutRef(IGF, likeType, collector);
2992+
StructLayoutFlags flags = StructLayoutFlags::Swift5Algorithm;
2993+
2994+
// Call swift_initRawStructMetadata().
2995+
IGF.Builder.CreateCall(IGM.getInitRawStructMetadataFunctionPointer(),
2996+
{metadata, IGM.getSize(Size(uintptr_t(flags))),
2997+
likeTypeLayout, IGM.getSize(count)});
2998+
}
2999+
29863000
static void emitInitializeValueMetadata(IRGenFunction &IGF,
29873001
NominalTypeDecl *nominalDecl,
29883002
llvm::Value *metadata,
@@ -2996,10 +3010,34 @@ static void emitInitializeValueMetadata(IRGenFunction &IGF,
29963010
IGM.getOptions().EnableLayoutStringValueWitnesses &&
29973011
IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation;
29983012

2999-
if (isa<StructDecl>(nominalDecl)) {
3013+
if (auto sd = dyn_cast<StructDecl>(nominalDecl)) {
30003014
auto &fixedTI = IGM.getTypeInfo(loweredTy);
30013015
if (isa<FixedTypeInfo>(fixedTI)) return;
30023016

3017+
// Use a different runtime function to initialize the value witness table
3018+
// if the struct has a raw layout. The existing swift_initStructMetadata
3019+
// is the wrong thing for these types.
3020+
if (auto rawLayout = nominalDecl->getAttrs().getAttribute<RawLayoutAttr>()) {
3021+
SILType loweredLikeType;
3022+
Size count;
3023+
3024+
if (auto likeType = rawLayout->getResolvedScalarLikeType(sd)) {
3025+
loweredLikeType = IGM.getLoweredType(AbstractionPattern::getOpaque(),
3026+
*likeType);
3027+
count = Size(-1);
3028+
} else if (auto likeArray = rawLayout->getResolvedArrayLikeTypeAndCount(sd)) {
3029+
auto likeType = likeArray->first;
3030+
loweredLikeType = IGM.getLoweredType(AbstractionPattern::getOpaque(),
3031+
likeType);
3032+
3033+
count = Size(likeArray->second);
3034+
}
3035+
3036+
emitInitializeRawLayout(IGF, loweredLikeType, count, loweredTy, metadata,
3037+
collector);
3038+
return;
3039+
}
3040+
30033041
if (useLayoutStrings) {
30043042
emitInitializeFieldOffsetVectorWithLayoutString(IGF, loweredTy, metadata,
30053043
isVWTMutable, collector);

lib/IRGen/GenRecord.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -863,7 +863,6 @@ class RecordTypeBuilder {
863863
fields.reserve(astFields.size());
864864
fieldTypesForLayout.reserve(astFields.size());
865865

866-
bool loadable = true;
867866
auto fieldsABIAccessible = FieldsAreABIAccessible;
868867

869868
unsigned explosionSize = 0;
@@ -880,7 +879,6 @@ class RecordTypeBuilder {
880879

881880
auto loadableFieldTI = dyn_cast<LoadableTypeInfo>(&fieldTI);
882881
if (!loadableFieldTI) {
883-
loadable = false;
884882
continue;
885883
}
886884

@@ -902,7 +900,7 @@ class RecordTypeBuilder {
902900
}
903901

904902
// Create the type info.
905-
if (loadable) {
903+
if (layout.isLoadable()) {
906904
assert(layout.isFixedLayout());
907905
assert(fieldsABIAccessible);
908906
return asImpl()->createLoadable(fields, std::move(layout), explosionSize);

lib/IRGen/GenStruct.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,35 @@ namespace {
10881088
fields.push_back(
10891089
field.getTypeInfo().buildTypeLayoutEntry(IGM, fieldTy, useStructLayouts));
10901090
}
1091+
1092+
auto decl = T.getASTType()->getStructOrBoundGenericStruct();
1093+
auto rawLayout = decl->getAttrs().getAttribute<RawLayoutAttr>();
1094+
1095+
// If we have a raw layout struct who is non-fixed size, it means the
1096+
// layout of the struct is dependent on the archetype of the thing it's
1097+
// like.
1098+
if (rawLayout) {
1099+
SILType loweredLikeType;
1100+
1101+
if (auto likeType = rawLayout->getResolvedScalarLikeType(decl)) {
1102+
loweredLikeType = IGM.getLoweredType(*likeType);
1103+
} else if (auto likeArray = rawLayout->getResolvedArrayLikeTypeAndCount(decl)) {
1104+
loweredLikeType = IGM.getLoweredType(likeArray->first);
1105+
}
1106+
1107+
// The given struct type T that we're building may be in a generic
1108+
// environment that is different than that which was built our
1109+
// resolved rawLayout like type. Map our like type into the given
1110+
// environment.
1111+
auto subs = T.getASTType()->getContextSubstitutionMap(
1112+
IGM.getSwiftModule(), decl);
1113+
1114+
loweredLikeType = loweredLikeType.subst(IGM.getSILModule(), subs);
1115+
1116+
return IGM.getTypeInfo(loweredLikeType).buildTypeLayoutEntry(IGM,
1117+
loweredLikeType, useStructLayouts);
1118+
}
1119+
10911120
assert(!fields.empty() &&
10921121
"Empty structs should not be NonFixedStructTypeInfo");
10931122

@@ -1244,8 +1273,7 @@ namespace {
12441273
}
12451274

12461275
StructLayout performLayout(ArrayRef<const TypeInfo *> fieldTypes) {
1247-
return StructLayout(IGM, TheStruct->getAnyNominal(),
1248-
LayoutKind::NonHeapObject,
1276+
return StructLayout(IGM, TheStruct, LayoutKind::NonHeapObject,
12491277
LayoutStrategy::Optimal, fieldTypes, StructTy);
12501278
}
12511279
};

lib/IRGen/GenTuple.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ namespace {
512512
}
513513

514514
StructLayout performLayout(ArrayRef<const TypeInfo *> fieldTypes) {
515-
return StructLayout(IGM, /*decl=*/nullptr, LayoutKind::NonHeapObject,
515+
return StructLayout(IGM, /*type=*/ llvm::None, LayoutKind::NonHeapObject,
516516
LayoutStrategy::Universal, fieldTypes);
517517
}
518518
};

lib/IRGen/GenType.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2437,6 +2437,17 @@ namespace {
24372437
if (IGM.isResilient(decl, ResilienceExpansion::Maximal))
24382438
return true;
24392439

2440+
auto rawLayout = decl->getAttrs().getAttribute<RawLayoutAttr>();
2441+
2442+
// If our struct has a raw layout, it may be dependent on the like type.
2443+
if (rawLayout) {
2444+
if (auto likeType = rawLayout->getResolvedScalarLikeType(decl)) {
2445+
return visit((*likeType)->getCanonicalType());
2446+
} else if (auto likeArray = rawLayout->getResolvedArrayLikeTypeAndCount(decl)) {
2447+
return visit(likeArray->first->getCanonicalType());
2448+
}
2449+
}
2450+
24402451
for (auto field : decl->getStoredProperties()) {
24412452
if (visit(field->getInterfaceType()->getCanonicalType()))
24422453
return true;

lib/IRGen/StructLayout.cpp

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,17 @@ static bool requiresHeapHeader(LayoutKind kind) {
4343

4444
/// Perform structure layout on the given types.
4545
StructLayout::StructLayout(IRGenModule &IGM,
46-
NominalTypeDecl *decl,
46+
llvm::Optional<CanType> type,
4747
LayoutKind layoutKind,
4848
LayoutStrategy strategy,
4949
ArrayRef<const TypeInfo *> types,
5050
llvm::StructType *typeToFill) {
51+
NominalTypeDecl *decl = nullptr;
52+
53+
if (type) {
54+
decl = type->getAnyNominal();
55+
}
56+
5157
Elements.reserve(types.size());
5258

5359
// Fill in the Elements array.
@@ -73,7 +79,7 @@ StructLayout::StructLayout(IRGenModule &IGM,
7379
if (decl) {
7480
rawLayout = decl->getAttrs().getAttribute<RawLayoutAttr>();
7581
}
76-
if (rawLayout) {
82+
if (rawLayout && type) {
7783
auto sd = cast<StructDecl>(decl);
7884
IsKnownTriviallyDestroyable = deinit;
7985
IsKnownBitwiseTakable = IsBitwiseTakable;
@@ -82,6 +88,7 @@ StructLayout::StructLayout(IRGenModule &IGM,
8288
IsKnownCopyable = copyable;
8389
assert(builder.getHeaderSize() == Size(0));
8490
headerSize = Size(0);
91+
IsLoadable = false;
8592

8693
auto &Diags = IGM.Context.Diags;
8794
// Fixed size and alignment specified.
@@ -100,9 +107,12 @@ StructLayout::StructLayout(IRGenModule &IGM,
100107
IsFixedLayout = true;
101108
IsKnownAlwaysFixedSize = IsFixedSize;
102109
} else if (auto likeType = rawLayout->getResolvedScalarLikeType(sd)) {
103-
const TypeInfo &likeTypeInfo
104-
= IGM.getTypeInfoForUnlowered(AbstractionPattern::getOpaque(),
105-
*likeType);
110+
// If our likeType is dependent, then all calls to try and lay it out will
111+
// be non-fixed, but in a concrete case we want a fixed layout, so try to
112+
// substitute it out.
113+
auto subs = (*type)->getContextSubstitutionMap(IGM.getSwiftModule(), decl);
114+
auto loweredLikeType = IGM.getLoweredType(likeType->subst(subs));
115+
const TypeInfo &likeTypeInfo = IGM.getTypeInfo(loweredLikeType);
106116

107117
// Take layout attributes from the like type.
108118
if (const FixedTypeInfo *likeFixedType = dyn_cast<FixedTypeInfo>(&likeTypeInfo)) {
@@ -121,9 +131,9 @@ StructLayout::StructLayout(IRGenModule &IGM,
121131
auto elementType = likeArray->first;
122132
unsigned count = likeArray->second;
123133

124-
const TypeInfo &likeTypeInfo
125-
= IGM.getTypeInfoForUnlowered(AbstractionPattern::getOpaque(),
126-
elementType);
134+
auto subs = (*type)->getContextSubstitutionMap(IGM.getSwiftModule(), decl);
135+
auto loweredElementType = IGM.getLoweredType(elementType.subst(subs));
136+
const TypeInfo &likeTypeInfo = IGM.getTypeInfo(loweredElementType);
127137

128138
// Take layout attributes from the like type.
129139
if (const FixedTypeInfo *likeFixedType = dyn_cast<FixedTypeInfo>(&likeTypeInfo)) {
@@ -155,11 +165,6 @@ StructLayout::StructLayout(IRGenModule &IGM,
155165
}
156166
} else {
157167
Ty = (typeToFill ? typeToFill : IGM.OpaqueTy);
158-
159-
// TODO: For types with dependent layout, the metadata initialization also
160-
// has to be updated to account for the raw layout description.
161-
Diags.diagnose(rawLayout->getLocation(),
162-
diag::raw_layout_dynamic_type_layout_unsupported);
163168
}
164169
} else {
165170
bool nonEmpty = builder.addFields(Elements, strategy);
@@ -174,6 +179,7 @@ StructLayout::StructLayout(IRGenModule &IGM,
174179
headerSize = builder.getHeaderSize();
175180
SpareBits.clear();
176181
IsFixedLayout = true;
182+
IsLoadable = true;
177183
IsKnownTriviallyDestroyable = deinit;
178184
IsKnownBitwiseTakable = IsBitwiseTakable;
179185
IsKnownAlwaysFixedSize = IsFixedSize;
@@ -185,6 +191,7 @@ StructLayout::StructLayout(IRGenModule &IGM,
185191
headerSize = builder.getHeaderSize();
186192
SpareBits = builder.getSpareBits();
187193
IsFixedLayout = builder.isFixedLayout();
194+
IsLoadable = builder.isLoadable();
188195
IsKnownTriviallyDestroyable = deinit & builder.isTriviallyDestroyable();
189196
IsKnownBitwiseTakable = builder.isBitwiseTakable();
190197
IsKnownAlwaysFixedSize = builder.isAlwaysFixedSize();
@@ -379,6 +386,7 @@ bool StructLayoutBuilder::addField(ElementLayout &elt,
379386
IsKnownTriviallyDestroyable &= eltTI.isTriviallyDestroyable(ResilienceExpansion::Maximal);
380387
IsKnownBitwiseTakable &= eltTI.isBitwiseTakable(ResilienceExpansion::Maximal);
381388
IsKnownAlwaysFixedSize &= eltTI.isFixedSize(ResilienceExpansion::Minimal);
389+
IsLoadable &= eltTI.isLoadable();
382390

383391
if (eltTI.isKnownEmpty(ResilienceExpansion::Maximal)) {
384392
addEmptyElement(elt);

lib/IRGen/StructLayout.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ class StructLayoutBuilder {
283283
SmallVector<SpareBitVector, 8> CurSpareBits;
284284
unsigned NextNonFixedOffsetIndex = 0;
285285
bool IsFixedLayout = true;
286+
bool IsLoadable = true;
286287
IsTriviallyDestroyable_t IsKnownTriviallyDestroyable = IsTriviallyDestroyable;
287288
IsBitwiseTakable_t IsKnownBitwiseTakable = IsBitwiseTakable;
288289
IsCopyable_t IsKnownCopyable = IsCopyable;
@@ -327,6 +328,9 @@ class StructLayoutBuilder {
327328
/// Return whether the structure has a fixed-size layout.
328329
bool isFixedLayout() const { return IsFixedLayout; }
329330

331+
/// Return whether the structure has a loadable layout.
332+
bool isLoadable() const { return IsLoadable; }
333+
330334
/// Return whether the structure is known to be POD in the local
331335
/// resilience scope.
332336
IsTriviallyDestroyable_t isTriviallyDestroyable() const { return IsKnownTriviallyDestroyable; }
@@ -402,6 +406,9 @@ class StructLayout {
402406
/// alignment are exact.
403407
bool IsFixedLayout;
404408

409+
/// Whether this layout
410+
bool IsLoadable;
411+
405412
IsTriviallyDestroyable_t IsKnownTriviallyDestroyable;
406413
IsBitwiseTakable_t IsKnownBitwiseTakable;
407414
IsCopyable_t IsKnownCopyable;
@@ -419,7 +426,7 @@ class StructLayout {
419426
/// layout must include the reference-counting header
420427
/// \param typeToFill - if present, must be an opaque type whose body
421428
/// will be filled with this layout
422-
StructLayout(IRGenModule &IGM, NominalTypeDecl *decl,
429+
StructLayout(IRGenModule &IGM, llvm::Optional<CanType> type,
423430
LayoutKind kind, LayoutStrategy strategy,
424431
ArrayRef<const TypeInfo *> fields,
425432
llvm::StructType *typeToFill = 0);
@@ -434,6 +441,7 @@ class StructLayout {
434441
headerSize(builder.getHeaderSize()),
435442
SpareBits(builder.getSpareBits()),
436443
IsFixedLayout(builder.isFixedLayout()),
444+
IsLoadable(builder.isLoadable()),
437445
IsKnownTriviallyDestroyable(builder.isTriviallyDestroyable()),
438446
IsKnownBitwiseTakable(builder.isBitwiseTakable()),
439447
IsKnownCopyable(builder.isCopyable()),
@@ -467,6 +475,7 @@ class StructLayout {
467475
}
468476

469477
bool isFixedLayout() const { return IsFixedLayout; }
478+
bool isLoadable() const { return IsLoadable; }
470479
llvm::Constant *emitSize(IRGenModule &IGM) const;
471480
llvm::Constant *emitAlignMask(IRGenModule &IGM) const;
472481

0 commit comments

Comments
 (0)