Skip to content

Commit 5fe7165

Browse files
authored
[IRGen] Add layout strings for generic and resilient types (#64023)
* [IRGen] Add layout strings for generic and resilient types rdar://105837048 * Add some corner cases * Add flag to enable generic instantiation and some fixes * Fix resilient types * Fix metadata accessor function pointers in combined layout strings
1 parent 71a6c07 commit 5fe7165

File tree

15 files changed

+608
-83
lines changed

15 files changed

+608
-83
lines changed

include/swift/ABI/Metadata.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,11 @@ struct TargetMetadata {
340340
}
341341

342342
bool hasLayoutString() const {
343-
return getTypeContextDescriptor()->hasLayoutString();
343+
if (auto *contextDescriptor = getTypeContextDescriptor()) {
344+
return contextDescriptor->hasLayoutString();
345+
}
346+
347+
return false;
344348
}
345349

346350
// Define forwarders for value witnesses. These invoke this metadata's value

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ EXPERIMENTAL_FEATURE(AccessLevelOnImport, false)
125125

126126
/// Whether to enable experimental layout string value witnesses
127127
EXPERIMENTAL_FEATURE(LayoutStringValueWitnesses, true)
128+
EXPERIMENTAL_FEATURE(LayoutStringValueWitnessesInstantiation, true)
128129

129130
/// Whether to enable experimental differentiable programming features:
130131
/// `@differentiable` declaration attribute, etc.

include/swift/Runtime/Metadata.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,13 @@ void swift_initStructMetadata(StructMetadata *self,
650650
const TypeLayout * const *fieldTypes,
651651
uint32_t *fieldOffsets);
652652

653+
SWIFT_RUNTIME_EXPORT
654+
void swift_initStructMetadataWithLayoutString(StructMetadata *self,
655+
StructLayoutFlags flags,
656+
size_t numFields,
657+
const Metadata *const *fieldTypes,
658+
uint32_t *fieldOffsets);
659+
653660
/// Allocate the metadata for a class and copy fields from the given pattern.
654661
/// The final size of the metadata is calculated at runtime from the metadata
655662
/// bounds in the class descriptor.

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,20 @@ FUNCTION(InitStructMetadata,
12511251
ATTRS(NoUnwind),
12521252
EFFECT(MetaData))
12531253

1254+
// void swift_initStructMetadataWithLayoutString(Metadata *structType,
1255+
// StructLayoutFlags flags,
1256+
// size_t numFields,
1257+
// Metadata * const *fieldTypes,
1258+
// uint32_t *fieldOffsets);
1259+
FUNCTION(InitStructMetadataWithLayoutString,
1260+
swift_initStructMetadataWithLayoutString, C_CC, AlwaysAvailable,
1261+
RETURNS(VoidTy),
1262+
ARGS(TypeMetadataPtrTy, SizeTy, SizeTy,
1263+
TypeMetadataPtrPtrTy,
1264+
Int32Ty->getPointerTo()),
1265+
ATTRS(NoUnwind),
1266+
EFFECT(MetaData))
1267+
12541268
// void swift_initEnumMetadataSingleCase(Metadata *enumType,
12551269
// EnumLayoutFlags flags,
12561270
// TypeLayout *payload);

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3142,6 +3142,10 @@ static bool usesFeatureLayoutStringValueWitnesses(Decl *decl) {
31423142
return false;
31433143
}
31443144

3145+
static bool usesFeatureLayoutStringValueWitnessesInstantiation(Decl *decl) {
3146+
return false;
3147+
}
3148+
31453149
static bool usesFeatureModuleInterfaceExportAs(Decl *decl) {
31463150
return false;
31473151
}

lib/IRGen/GenMeta.cpp

Lines changed: 149 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2872,23 +2872,101 @@ static void emitInitializeFieldOffsetVector(IRGenFunction &IGF,
28722872
IGF.Builder.CreateLifetimeEnd(fields, IGM.getPointerSize() * numFields);
28732873
}
28742874

2875+
static void emitInitializeFieldOffsetVectorWithLayoutString(
2876+
IRGenFunction &IGF, SILType T, llvm::Value *metadata, bool isVWTMutable,
2877+
MetadataDependencyCollector *collector) {
2878+
auto &IGM = IGF.IGM;
2879+
assert(IGM.Context.LangOpts.hasFeature(
2880+
Feature::LayoutStringValueWitnessesInstantiation));
2881+
2882+
auto *target = T.getStructOrBoundGenericStruct();
2883+
2884+
llvm::Value *fieldVector =
2885+
emitAddressOfFieldOffsetVector(IGF, metadata, target).getAddress();
2886+
2887+
// Collect the stored properties of the type.
2888+
unsigned numFields = getNumFields(target);
2889+
2890+
// Ask the runtime to lay out the struct or class.
2891+
auto numFieldsV = IGM.getSize(Size(numFields));
2892+
2893+
// Fill out an array with the field type metadata records.
2894+
Address fieldsMetadata =
2895+
IGF.createAlloca(llvm::ArrayType::get(IGM.TypeMetadataPtrTy, numFields),
2896+
IGM.getPointerAlignment(), "fieldsMetadata");
2897+
IGF.Builder.CreateLifetimeStart(fieldsMetadata,
2898+
IGM.getPointerSize() * numFields);
2899+
fieldsMetadata = IGF.Builder.CreateStructGEP(fieldsMetadata, 0, Size(0));
2900+
2901+
unsigned index = 0;
2902+
forEachField(IGM, target, [&](Field field) {
2903+
assert(field.isConcrete() &&
2904+
"initializing offset vector for type with missing member?");
2905+
SILType propTy = field.getType(IGM, T);
2906+
llvm::Value *fieldMetatype;
2907+
if (auto ownership = propTy.getReferenceStorageOwnership()) {
2908+
switch (*ownership) {
2909+
case ReferenceOwnership::Weak:
2910+
fieldMetatype = llvm::Constant::getIntegerValue(
2911+
IGM.TypeMetadataPtrTy, APInt(IGM.IntPtrTy->getBitWidth(), 0x7));
2912+
break;
2913+
case ReferenceOwnership::Strong:
2914+
case ReferenceOwnership::Unowned:
2915+
case ReferenceOwnership::Unmanaged:
2916+
llvm_unreachable("Unmanaged reference should have been lowered");
2917+
}
2918+
} else {
2919+
auto request = DynamicMetadataRequest::getNonBlocking(
2920+
MetadataState::LayoutComplete, collector);
2921+
fieldMetatype = IGF.emitTypeMetadataRefForLayout(propTy, request);
2922+
}
2923+
2924+
Address fieldMetatypeAddr = IGF.Builder.CreateConstArrayGEP(
2925+
fieldsMetadata, index, IGM.getPointerSize());
2926+
IGF.Builder.CreateStore(fieldMetatype, fieldMetatypeAddr);
2927+
++index;
2928+
});
2929+
assert(index == numFields);
2930+
2931+
// Compute struct layout flags.
2932+
StructLayoutFlags flags = StructLayoutFlags::Swift5Algorithm;
2933+
if (isVWTMutable)
2934+
flags |= StructLayoutFlags::IsVWTMutable;
2935+
2936+
// Call swift_initStructMetadataWithLayoutString().
2937+
IGF.Builder.CreateCall(
2938+
IGM.getInitStructMetadataWithLayoutStringFunctionPointer(),
2939+
{metadata, IGM.getSize(Size(uintptr_t(flags))), numFieldsV,
2940+
fieldsMetadata.getAddress(), fieldVector});
2941+
2942+
IGF.Builder.CreateLifetimeEnd(fieldsMetadata,
2943+
IGM.getPointerSize() * numFields);
2944+
}
2945+
28752946
static void emitInitializeValueMetadata(IRGenFunction &IGF,
28762947
NominalTypeDecl *nominalDecl,
28772948
llvm::Value *metadata,
28782949
bool isVWTMutable,
28792950
MetadataDependencyCollector *collector) {
2880-
auto loweredTy =
2881-
IGF.IGM.getLoweredType(nominalDecl->getDeclaredTypeInContext());
2951+
auto &IGM = IGF.IGM;
2952+
auto loweredTy = IGM.getLoweredType(nominalDecl->getDeclaredTypeInContext());
28822953

28832954
if (isa<StructDecl>(nominalDecl)) {
2884-
auto &fixedTI = IGF.IGM.getTypeInfo(loweredTy);
2955+
auto &fixedTI = IGM.getTypeInfo(loweredTy);
28852956
if (isa<FixedTypeInfo>(fixedTI)) return;
28862957

2887-
emitInitializeFieldOffsetVector(IGF, loweredTy, metadata, isVWTMutable,
2888-
collector);
2958+
if (IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnesses) &&
2959+
IGM.Context.LangOpts.hasFeature(
2960+
Feature::LayoutStringValueWitnessesInstantiation)) {
2961+
emitInitializeFieldOffsetVectorWithLayoutString(IGF, loweredTy, metadata,
2962+
isVWTMutable, collector);
2963+
} else {
2964+
emitInitializeFieldOffsetVector(IGF, loweredTy, metadata, isVWTMutable,
2965+
collector);
2966+
}
28892967
} else {
28902968
assert(isa<EnumDecl>(nominalDecl));
2891-
auto &strategy = getEnumImplStrategy(IGF.IGM, loweredTy);
2969+
auto &strategy = getEnumImplStrategy(IGM, loweredTy);
28922970
strategy.initializeMetadata(IGF, metadata, isVWTMutable, loweredTy,
28932971
collector);
28942972
}
@@ -2996,11 +3074,15 @@ namespace {
29963074
llvm::Constant *emitLayoutString() {
29973075
if (!IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnesses))
29983076
return nullptr;
2999-
auto lowered = getLoweredType();
3000-
auto &typeLayoutEntry = IGM.getTypeLayoutEntry(lowered, /*useStructLayouts*/true);
3077+
auto lowered = getLoweredTypeInPrimaryContext(
3078+
IGM, Target->getDeclaredType()->getCanonicalType());
3079+
auto &ti = IGM.getTypeInfo(lowered);
3080+
auto *typeLayoutEntry =
3081+
ti.buildTypeLayoutEntry(IGM, lowered, /*useStructLayouts*/ true);
30013082
auto genericSig =
30023083
lowered.getNominalOrBoundGenericNominal()->getGenericSignature();
3003-
return typeLayoutEntry.layoutString(IGM, genericSig);
3084+
3085+
return typeLayoutEntry->layoutString(IGM, genericSig);
30043086
}
30053087

30063088
llvm::Constant *getLayoutString() {
@@ -3072,12 +3154,11 @@ namespace {
30723154
if (HasDependentMetadata)
30733155
asImpl().emitInitializeMetadata(IGF, metadata, false, collector);
30743156

3075-
3076-
if (!IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnesses)) {
3157+
if (IGM.Context.LangOpts.hasFeature(
3158+
Feature::LayoutStringValueWitnesses)) {
30773159
if (auto *layoutString = getLayoutString()) {
30783160
auto layoutStringCast = IGF.Builder.CreateBitCast(layoutString,
30793161
IGM.Int8PtrTy);
3080-
30813162
IGF.Builder.CreateCall(
30823163
IGM.getGenericInstantiateLayoutStringFunctionPointer(),
30833164
{layoutStringCast, metadata});
@@ -3650,11 +3731,15 @@ namespace {
36503731
llvm::Constant *emitLayoutString() {
36513732
if (!IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnesses))
36523733
return nullptr;
3653-
auto lowered = getLoweredType();
3654-
auto &typeLayoutEntry = IGM.getTypeLayoutEntry(lowered, /*useStructLayouts*/true);
3734+
auto lowered = getLoweredTypeInPrimaryContext(
3735+
IGM, Target->getDeclaredType()->getCanonicalType());
3736+
auto &ti = IGM.getTypeInfo(lowered);
3737+
auto *typeLayoutEntry =
3738+
ti.buildTypeLayoutEntry(IGM, lowered, /*useStructLayouts*/ true);
36553739
auto genericSig =
36563740
lowered.getNominalOrBoundGenericNominal()->getGenericSignature();
3657-
return typeLayoutEntry.layoutString(IGM, genericSig);
3741+
3742+
return typeLayoutEntry->layoutString(IGM, genericSig);
36583743
}
36593744

36603745
llvm::Constant *getLayoutString() {
@@ -4843,11 +4928,22 @@ namespace {
48434928
B.addInt(IGM.MetadataKindTy, unsigned(getMetadataKind(Target)));
48444929
}
48454930

4931+
bool hasLayoutString() {
4932+
if (!IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnesses)) {
4933+
return false;
4934+
}
4935+
4936+
if (IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnessesInstantiation)) {
4937+
return !!getLayoutString() || needsSingletonMetadataInitialization(IGM, Target);
4938+
}
4939+
4940+
return !!getLayoutString();
4941+
}
4942+
48464943
llvm::Constant *emitNominalTypeDescriptor() {
4847-
auto hasLayoutString = !!getLayoutString();
48484944
auto descriptor =
48494945
StructContextDescriptorBuilder(IGM, Target, RequireMetadata,
4850-
hasLayoutString).emit();
4946+
hasLayoutString()).emit();
48514947
return descriptor;
48524948
}
48534949

@@ -4878,11 +4974,15 @@ namespace {
48784974
llvm::Constant *emitLayoutString() {
48794975
if (!IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnesses))
48804976
return nullptr;
4881-
auto lowered = getLoweredType();
4882-
auto &typeLayoutEntry = IGM.getTypeLayoutEntry(lowered, /*useStructLayouts*/true);
4977+
auto lowered = getLoweredTypeInPrimaryContext(
4978+
IGM, Target->getDeclaredType()->getCanonicalType());
4979+
auto &ti = IGM.getTypeInfo(lowered);
4980+
auto *typeLayoutEntry =
4981+
ti.buildTypeLayoutEntry(IGM, lowered, /*useStructLayouts*/ true);
48834982
auto genericSig =
48844983
lowered.getNominalOrBoundGenericNominal()->getGenericSignature();
4885-
return typeLayoutEntry.layoutString(IGM, genericSig);
4984+
4985+
return typeLayoutEntry->layoutString(IGM, genericSig);
48864986
}
48874987

48884988
llvm::Constant *getLayoutString() {
@@ -5021,9 +5121,22 @@ namespace {
50215121
// We just assume this might happen.
50225122
}
50235123

5124+
bool hasLayoutString() {
5125+
if (!IGM.Context.LangOpts.hasFeature(
5126+
Feature::LayoutStringValueWitnesses)) {
5127+
return false;
5128+
}
5129+
return !!getLayoutString() ||
5130+
IGM.Context.LangOpts.hasFeature(
5131+
Feature::LayoutStringValueWitnessesInstantiation);
5132+
}
5133+
50245134
llvm::Constant *emitNominalTypeDescriptor() {
5025-
return StructContextDescriptorBuilder(IGM, Target, RequireMetadata,
5026-
/*hasLayoutString*/ false).emit();
5135+
5136+
return StructContextDescriptorBuilder(
5137+
IGM, Target, RequireMetadata,
5138+
/*hasLayoutString*/ hasLayoutString())
5139+
.emit();
50275140
}
50285141

50295142
GenericMetadataPatternFlags getPatternFlags() {
@@ -5122,8 +5235,8 @@ namespace {
51225235
bool hasCompletionFunction() {
51235236
// TODO: Once we store layout string pointers on the metadata pattern, we
51245237
// don't have to emit completion functions for all generic types anymore.
5125-
return IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnesses) ||
5126-
!isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType()));
5238+
return !isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType())) ||
5239+
!!getLayoutString();
51275240
}
51285241
};
51295242

@@ -5275,11 +5388,15 @@ namespace {
52755388
llvm::Constant *emitLayoutString() {
52765389
if (!IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnesses))
52775390
return nullptr;
5278-
auto lowered = getLoweredType();
5279-
auto &typeLayoutEntry = IGM.getTypeLayoutEntry(lowered, /*useStructLayouts*/true);
5391+
auto lowered = getLoweredTypeInPrimaryContext(
5392+
IGM, Target->getDeclaredType()->getCanonicalType());
5393+
auto &ti = IGM.getTypeInfo(lowered);
5394+
auto *typeLayoutEntry =
5395+
ti.buildTypeLayoutEntry(IGM, lowered, /*useStructLayouts*/ true);
52805396
auto genericSig =
52815397
lowered.getNominalOrBoundGenericNominal()->getGenericSignature();
5282-
return typeLayoutEntry.layoutString(IGM, genericSig);
5398+
5399+
return typeLayoutEntry->layoutString(IGM, genericSig);
52835400
}
52845401

52855402
llvm::Constant *getLayoutString() {
@@ -5496,8 +5613,9 @@ namespace {
54965613
}
54975614

54985615
llvm::Constant *emitNominalTypeDescriptor() {
5499-
return EnumContextDescriptorBuilder(IGM, Target, RequireMetadata,
5500-
/*hasLayoutString*/ false)
5616+
return EnumContextDescriptorBuilder(
5617+
IGM, Target, RequireMetadata,
5618+
/*hasLayoutString*/ !!getLayoutString())
55015619
.emit();
55025620
}
55035621

@@ -5518,7 +5636,8 @@ namespace {
55185636
}
55195637

55205638
bool hasCompletionFunction() {
5521-
return !isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType()));
5639+
return !isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType())) ||
5640+
!!getLayoutString();
55225641
}
55235642
};
55245643

0 commit comments

Comments
 (0)