Skip to content

Commit 44198d1

Browse files
authored
Merge pull request swiftlang#67611 from Azoy/raw-types-are-cool!
[WIP] Implement dependent layouts for raw types
2 parents 98ada1b + c20ab10 commit 44198d1

19 files changed

+414
-31
lines changed

include/swift/AST/ASTContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,10 @@ class ASTContext final {
941941
/// descriptors.
942942
AvailabilityContext getSignedDescriptorAvailability();
943943

944+
/// Get the runtime availability of the swift_initRawStructMetadata entrypoint
945+
/// that fixes up the value witness table of @_rawLayout dependent types.
946+
AvailabilityContext getInitRawStructMetadataAvailability();
947+
944948
/// Get the runtime availability of features introduced in the Swift 5.2
945949
/// compiler for the target platform.
946950
AvailabilityContext getSwift52Availability();

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+
int32_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+
// int32_t count);
2493+
FUNCTION(InitRawStructMetadata,
2494+
swift_initRawStructMetadata,
2495+
C_CC, AlwaysAvailable,
2496+
RETURNS(VoidTy),
2497+
ARGS(TypeMetadataPtrTy, SizeTy, Int8PtrPtrTy->getPointerTo(0), Int32Ty),
2498+
ATTRS(NoUnwind),
2499+
EFFECT(MetaData))
2500+
24892501
#undef RETURNS
24902502
#undef ARGS
24912503
#undef ATTRS

lib/AST/Availability.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,11 @@ ASTContext::getSignedDescriptorAvailability() {
573573
return getSwift59Availability();
574574
}
575575

576+
AvailabilityContext
577+
ASTContext::getInitRawStructMetadataAvailability() {
578+
return getSwiftFutureAvailability();
579+
}
580+
576581
AvailabilityContext ASTContext::getSwift52Availability() {
577582
auto target = LangOpts.Target;
578583

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: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2983,6 +2983,116 @@ static void emitInitializeFieldOffsetVectorWithLayoutString(
29832983
IGM.getPointerSize() * numFields);
29842984
}
29852985

2986+
static void emitInitializeRawLayoutOld(IRGenFunction &IGF, SILType likeType,
2987+
int32_t count, SILType T,
2988+
llvm::Value *metadata,
2989+
MetadataDependencyCollector *collector) {
2990+
auto &IGM = IGF.IGM;
2991+
2992+
// This is the list of field type layouts that we're going to pass to the init
2993+
// function. This will only ever hold 1 field which is the temporary one we're
2994+
// going to build up from our like type's layout.
2995+
auto fieldLayouts = IGF.createAlloca(
2996+
llvm::ArrayType::get(IGM.TypeLayoutTy->getPointerTo(), 1),
2997+
IGM.getPointerAlignment(), "fieldLayouts");
2998+
IGF.Builder.CreateLifetimeStart(fieldLayouts, IGM.getPointerSize());
2999+
3000+
// We're going to pretend that this is our field offset vector for the init to
3001+
// write to. We don't actually have fields, so we don't want to write a field
3002+
// offset in our metadata.
3003+
auto fieldOffsets = IGF.createAlloca(IGM.Int32Ty, Alignment(4), "fieldOffsets");
3004+
IGF.Builder.CreateLifetimeStart(fieldOffsets, Size(4));
3005+
3006+
// We need to make a temporary type layout with most of the same information
3007+
// from the type we're like.
3008+
auto ourTypeLayout = IGF.createAlloca(IGM.TypeLayoutTy,
3009+
IGM.getPointerAlignment(),
3010+
"ourTypeLayout");
3011+
IGF.Builder.CreateLifetimeStart(ourTypeLayout, IGM.getPointerSize());
3012+
3013+
// Put our temporary type layout in the list of layouts we're using to
3014+
// initialize.
3015+
IGF.Builder.CreateStore(ourTypeLayout.getAddress(), fieldLayouts);
3016+
3017+
// Get the like type's type layout.
3018+
auto likeTypeLayout = emitTypeLayoutRef(IGF, likeType, collector);
3019+
3020+
// Grab the size, stride, and alignmentMask out of the layout.
3021+
auto loadedTyLayout = IGF.Builder.CreateLoad(
3022+
Address(likeTypeLayout, IGM.TypeLayoutTy, IGM.getPointerAlignment()),
3023+
"typeLayout");
3024+
auto size = IGF.Builder.CreateExtractValue(loadedTyLayout, 0, "size");
3025+
auto stride = IGF.Builder.CreateExtractValue(loadedTyLayout, 1, "stride");
3026+
auto flags = IGF.Builder.CreateExtractValue(loadedTyLayout, 2, "flags");
3027+
auto xi = IGF.Builder.CreateExtractValue(loadedTyLayout, 3, "xi");
3028+
3029+
// This will zero out the other bits.
3030+
auto alignMask = IGF.Builder.CreateAnd(flags,
3031+
ValueWitnessFlags::AlignmentMask,
3032+
"alignMask");
3033+
3034+
// Set the isNonPOD bit. This is important because older runtimes will attempt
3035+
// to replace various vwt functions with more optimized ones. In this case, we
3036+
// want to preserve the fact that noncopyable types have unreachable copy vwt
3037+
// functions.
3038+
auto vwtFlags = IGF.Builder.CreateOr(alignMask,
3039+
ValueWitnessFlags::IsNonPOD,
3040+
"vwtFlags");
3041+
3042+
// Count is only ever -1 if we're not an array like layout.
3043+
if (count != -1) {
3044+
stride = IGF.Builder.CreateMul(stride, IGM.getSize(Size(count)));
3045+
size = stride;
3046+
}
3047+
3048+
llvm::Value *resultAgg = llvm::UndefValue::get(IGM.TypeLayoutTy);
3049+
resultAgg = IGF.Builder.CreateInsertValue(resultAgg, size, 0);
3050+
resultAgg = IGF.Builder.CreateInsertValue(resultAgg, stride, 1);
3051+
resultAgg = IGF.Builder.CreateInsertValue(resultAgg, vwtFlags, 2);
3052+
resultAgg = IGF.Builder.CreateInsertValue(resultAgg, xi, 3);
3053+
3054+
IGF.Builder.CreateStore(resultAgg, ourTypeLayout);
3055+
3056+
StructLayoutFlags fnFlags = StructLayoutFlags::Swift5Algorithm;
3057+
3058+
// Call swift_initStructMetadata().
3059+
IGF.Builder.CreateCall(IGM.getInitStructMetadataFunctionPointer(),
3060+
{metadata, IGM.getSize(Size(uintptr_t(fnFlags))),
3061+
IGM.getSize(Size(1)), fieldLayouts.getAddress(),
3062+
fieldOffsets.getAddress()});
3063+
3064+
IGF.Builder.CreateLifetimeEnd(ourTypeLayout, IGM.getPointerSize());
3065+
IGF.Builder.CreateLifetimeEnd(fieldOffsets, Size(4));
3066+
IGF.Builder.CreateLifetimeEnd(fieldLayouts, IGM.getPointerSize());
3067+
}
3068+
3069+
static void emitInitializeRawLayout(IRGenFunction &IGF, SILType likeType,
3070+
int32_t count, SILType T,
3071+
llvm::Value *metadata,
3072+
MetadataDependencyCollector *collector) {
3073+
// If our deployment target doesn't contain the new swift_initRawStructMetadata,
3074+
// emit a call to the swift_initStructMetadata tricking it into thinking
3075+
// we have a single field.
3076+
auto deploymentAvailability =
3077+
AvailabilityContext::forDeploymentTarget(IGF.IGM.Context);
3078+
auto initRawAvail = IGF.IGM.Context.getInitRawStructMetadataAvailability();
3079+
3080+
if (!IGF.IGM.Context.LangOpts.DisableAvailabilityChecking &&
3081+
!deploymentAvailability.isContainedIn(initRawAvail)) {
3082+
emitInitializeRawLayoutOld(IGF, likeType, count, T, metadata, collector);
3083+
return;
3084+
}
3085+
3086+
auto &IGM = IGF.IGM;
3087+
auto likeTypeLayout = emitTypeLayoutRef(IGF, likeType, collector);
3088+
StructLayoutFlags flags = StructLayoutFlags::Swift5Algorithm;
3089+
3090+
// Call swift_initRawStructMetadata().
3091+
IGF.Builder.CreateCall(IGM.getInitRawStructMetadataFunctionPointer(),
3092+
{metadata, IGM.getSize(Size(uintptr_t(flags))),
3093+
likeTypeLayout, IGM.getInt32(count)});
3094+
}
3095+
29863096
static void emitInitializeValueMetadata(IRGenFunction &IGF,
29873097
NominalTypeDecl *nominalDecl,
29883098
llvm::Value *metadata,
@@ -2996,10 +3106,33 @@ static void emitInitializeValueMetadata(IRGenFunction &IGF,
29963106
IGM.getOptions().EnableLayoutStringValueWitnesses &&
29973107
IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation;
29983108

2999-
if (isa<StructDecl>(nominalDecl)) {
3109+
if (auto sd = dyn_cast<StructDecl>(nominalDecl)) {
30003110
auto &fixedTI = IGM.getTypeInfo(loweredTy);
30013111
if (isa<FixedTypeInfo>(fixedTI)) return;
30023112

3113+
// Use a different runtime function to initialize the value witness table
3114+
// if the struct has a raw layout. The existing swift_initStructMetadata
3115+
// is the wrong thing for these types.
3116+
if (auto rawLayout = nominalDecl->getAttrs().getAttribute<RawLayoutAttr>()) {
3117+
SILType loweredLikeType;
3118+
int32_t count = -1;
3119+
3120+
if (auto likeType = rawLayout->getResolvedScalarLikeType(sd)) {
3121+
loweredLikeType = IGM.getLoweredType(AbstractionPattern::getOpaque(),
3122+
*likeType);
3123+
} else if (auto likeArray = rawLayout->getResolvedArrayLikeTypeAndCount(sd)) {
3124+
auto likeType = likeArray->first;
3125+
loweredLikeType = IGM.getLoweredType(AbstractionPattern::getOpaque(),
3126+
likeType);
3127+
3128+
count = likeArray->second;
3129+
}
3130+
3131+
emitInitializeRawLayout(IGF, loweredLikeType, count, loweredTy, metadata,
3132+
collector);
3133+
return;
3134+
}
3135+
30033136
if (useLayoutStrings) {
30043137
emitInitializeFieldOffsetVectorWithLayoutString(IGF, loweredTy, metadata,
30053138
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;

0 commit comments

Comments
 (0)