Skip to content

Commit 7e35c64

Browse files
committed
[metadata prespecialization] Create enum records.
Extracted implementation of SpecializedGenericStructMetadataBuilder into SpecializedGenericNominalMetadataBuilderBase, a CRTP with a template template argument for the CRTP superclass and a template argument for the implementation. That new type is now subclassed by SpecializedGenericStructMetadataBuilder. Additionally, this new type is also subclassed by the newly added SpecializedGenericEnumMetadataBuilder which is responsible for build the prespecialization of generic enum metadata. rdar://problem/56960887
1 parent e26b216 commit 7e35c64

File tree

5 files changed

+178
-41
lines changed

5 files changed

+178
-41
lines changed

include/swift/ABI/Metadata.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1426,6 +1426,32 @@ struct TargetEnumMetadata : public TargetValueMetadata<Runtime> {
14261426
return *asWords;
14271427
}
14281428

1429+
bool isCanonicalStaticallySpecializedGenericMetadata() const {
1430+
auto *description = getDescription();
1431+
if (!description->isGeneric())
1432+
return false;
1433+
1434+
auto *trailingFlags = getTrailingFlags();
1435+
if (trailingFlags == nullptr)
1436+
return false;
1437+
1438+
return trailingFlags->isCanonicalStaticSpecialization();
1439+
}
1440+
1441+
const MetadataTrailingFlags *getTrailingFlags() const {
1442+
auto description = getDescription();
1443+
auto flags = description->getFullGenericContextHeader()
1444+
.DefaultInstantiationPattern->PatternFlags;
1445+
if (!flags.hasTrailingFlags())
1446+
return nullptr;
1447+
auto offset =
1448+
getGenericArgumentOffset() +
1449+
description->getFullGenericContextHeader().Base.getNumArguments() +
1450+
(hasPayloadSize() ? 1 : 0);
1451+
auto asWords = reinterpret_cast<const void *const *>(this);
1452+
return reinterpret_cast<const MetadataTrailingFlags *>(asWords + offset);
1453+
}
1454+
14291455
static constexpr int32_t getGenericArgumentOffset() {
14301456
return sizeof(TargetEnumMetadata<Runtime>) / sizeof(StoredPointer);
14311457
}

lib/IRGen/EnumMetadataVisitor.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ template <class Impl> class EnumMetadataVisitor
6262
Target->getDeclaredTypeInContext()->getCanonicalType());
6363
if (strategy.needsPayloadSizeInMetadata())
6464
asImpl().addPayloadSize();
65+
66+
if (asImpl().hasTrailingFlags())
67+
asImpl().addTrailingFlags();
68+
}
69+
70+
bool hasTrailingFlags() {
71+
return Target->isGenericContext() &&
72+
IGM.shouldPrespecializeGenericMetadata();
6573
}
6674
};
6775

@@ -86,6 +94,7 @@ class EnumMetadataScanner : public EnumMetadataVisitor<Impl> {
8694
void addGenericWitnessTable(GenericRequirement requirement) { addPointer(); }
8795
void addPayloadSize() { addPointer(); }
8896
void noteStartOfTypeSpecificMembers() {}
97+
void addTrailingFlags() { addPointer(); }
8998

9099
private:
91100
void addPointer() {

lib/IRGen/GenMeta.cpp

Lines changed: 136 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1859,7 +1859,21 @@ void irgen::emitLazyMetadataAccessor(IRGenModule &IGM,
18591859

18601860
void irgen::emitLazySpecializedGenericTypeMetadata(IRGenModule &IGM,
18611861
CanType type) {
1862-
emitSpecializedGenericStructMetadata(IGM, type);
1862+
switch (type->getKind()) {
1863+
case TypeKind::Struct:
1864+
case TypeKind::BoundGenericStruct:
1865+
emitSpecializedGenericStructMetadata(IGM, type,
1866+
*type.getStructOrBoundGenericStruct());
1867+
break;
1868+
case TypeKind::Enum:
1869+
case TypeKind::BoundGenericEnum:
1870+
emitSpecializedGenericEnumMetadata(IGM, type,
1871+
*type.getEnumOrBoundGenericEnum());
1872+
break;
1873+
default:
1874+
llvm_unreachable("Cannot statically specialize types of kind other than "
1875+
"struct and enum.");
1876+
}
18631877
}
18641878

18651879
llvm::Constant *
@@ -3472,8 +3486,12 @@ namespace {
34723486
: public ValueMetadataBuilderBase<StructMetadataVisitor<Impl>> {
34733487
using super = ValueMetadataBuilderBase<StructMetadataVisitor<Impl>>;
34743488

3489+
bool HasUnfilledFieldOffset = false;
3490+
34753491
protected:
3476-
ConstantStructBuilder &B;
3492+
using ConstantBuilder = ConstantStructBuilder;
3493+
ConstantBuilder &B;
3494+
using NominalDecl = StructDecl;
34773495
using super::IGM;
34783496
using super::Target;
34793497
using super::asImpl;
@@ -3562,16 +3580,6 @@ namespace {
35623580

35633581
return flags;
35643582
}
3565-
};
3566-
3567-
class StructMetadataBuilder :
3568-
public StructMetadataBuilderBase<StructMetadataBuilder> {
3569-
3570-
bool HasUnfilledFieldOffset = false;
3571-
public:
3572-
StructMetadataBuilder(IRGenModule &IGM, StructDecl *theStruct,
3573-
ConstantStructBuilder &B)
3574-
: StructMetadataBuilderBase(IGM, theStruct, B) {}
35753583

35763584
void flagUnfilledFieldOffset() {
35773585
HasUnfilledFieldOffset = true;
@@ -3580,13 +3588,21 @@ namespace {
35803588
bool canBeConstant() {
35813589
return !HasUnfilledFieldOffset;
35823590
}
3591+
};
3592+
3593+
class StructMetadataBuilder
3594+
: public StructMetadataBuilderBase<StructMetadataBuilder> {
3595+
public:
3596+
StructMetadataBuilder(IRGenModule &IGM, StructDecl *theStruct,
3597+
ConstantStructBuilder &B)
3598+
: StructMetadataBuilderBase(IGM, theStruct, B) {}
35833599

35843600
void createMetadataAccessFunction() {
35853601
createNonGenericMetadataAccessFunction(IGM, Target);
35863602
maybeCreateSingletonMetadataInitialization();
35873603
}
35883604
};
3589-
3605+
35903606
/// Emit a value witness table for a fixed-layout generic type, or a template
35913607
/// if the value witness table is dependent on generic parameters.
35923608
static ConstantReference
@@ -3710,24 +3726,25 @@ namespace {
37103726
}
37113727
};
37123728

3713-
class SpecializedGenericStructMetadataBuilder
3714-
: public StructMetadataBuilderBase<
3715-
SpecializedGenericStructMetadataBuilder> {
3716-
using super =
3717-
StructMetadataBuilderBase<SpecializedGenericStructMetadataBuilder>;
3729+
template <template <typename> class MetadataBuilderBase, typename Impl>
3730+
class SpecializedGenericNominalMetadataBuilderBase
3731+
: public MetadataBuilderBase<Impl> {
3732+
using super = MetadataBuilderBase<Impl>;
3733+
37183734
CanType type;
3719-
bool HasUnfilledFieldOffset = false;
37203735

37213736
protected:
37223737
using super::asImpl;
37233738
using super::getLoweredType;
37243739
using super::IGM;
37253740
using super::Target;
3741+
using typename super::ConstantBuilder;
3742+
using typename super::NominalDecl;
37263743

37273744
public:
3728-
SpecializedGenericStructMetadataBuilder(IRGenModule &IGM, CanType type,
3729-
StructDecl &decl,
3730-
ConstantStructBuilder &B)
3745+
SpecializedGenericNominalMetadataBuilderBase(IRGenModule &IGM, CanType type,
3746+
NominalDecl &decl,
3747+
ConstantBuilder &B)
37313748
: super(IGM, &decl, B), type(type) {}
37323749

37333750
void noteStartOfTypeSpecificMembers() {}
@@ -3750,7 +3767,7 @@ namespace {
37503767
auto t = requirement.TypeParameter.subst(genericSubstitutions());
37513768
ConstantReference ref = IGM.getAddrOfTypeMetadata(
37523769
CanType(t), SymbolReferenceKind::Relative_Direct);
3753-
B.add(ref.getDirectValue());
3770+
this->B.add(ref.getDirectValue());
37543771
}
37553772

37563773
void addGenericWitnessTable(GenericRequirement requirement) {
@@ -3773,7 +3790,7 @@ namespace {
37733790
addr = IGM.getAddrOfWitnessTable(rootConformance);
37743791
}
37753792

3776-
B.add(addr);
3793+
this->B.add(addr);
37773794
}
37783795

37793796
SubstitutionMap genericSubstitutions() {
@@ -3789,10 +3806,21 @@ namespace {
37893806

37903807
return flags;
37913808
}
3809+
};
3810+
3811+
class SpecializedGenericStructMetadataBuilder
3812+
: public SpecializedGenericNominalMetadataBuilderBase<
3813+
StructMetadataBuilderBase,
3814+
SpecializedGenericStructMetadataBuilder> {
3815+
using super = SpecializedGenericNominalMetadataBuilderBase<
3816+
StructMetadataBuilderBase, SpecializedGenericStructMetadataBuilder>;
37923817

3793-
void flagUnfilledFieldOffset() { HasUnfilledFieldOffset = true; }
37943818

3795-
bool canBeConstant() { return !HasUnfilledFieldOffset; }
3819+
public:
3820+
SpecializedGenericStructMetadataBuilder(IRGenModule &IGM, CanType type,
3821+
StructDecl &decl,
3822+
ConstantStructBuilder &B)
3823+
: super(IGM, type, decl, B) {}
37963824
};
37973825

37983826
} // end anonymous namespace
@@ -3828,8 +3856,8 @@ void irgen::emitStructMetadata(IRGenModule &IGM, StructDecl *structDecl) {
38283856
init.finishAndCreateFuture());
38293857
}
38303858

3831-
void irgen::emitSpecializedGenericStructMetadata(IRGenModule &IGM,
3832-
CanType type) {
3859+
void irgen::emitSpecializedGenericStructMetadata(IRGenModule &IGM, CanType type,
3860+
StructDecl &decl) {
38333861
Type ty = type.getPointer();
38343862
auto &context = type->getNominalOrBoundGenericNominal()->getASTContext();
38353863
PrettyStackTraceType stackTraceRAII(
@@ -3840,7 +3868,6 @@ void irgen::emitSpecializedGenericStructMetadata(IRGenModule &IGM,
38403868

38413869
bool isPattern = false;
38423870

3843-
auto &decl = *type.getStructOrBoundGenericStruct();
38443871
SpecializedGenericStructMetadataBuilder builder(IGM, type, decl, init);
38453872
builder.layout();
38463873

@@ -3871,9 +3898,13 @@ namespace {
38713898
class EnumMetadataBuilderBase
38723899
: public ValueMetadataBuilderBase<EnumMetadataVisitor<Impl>> {
38733900
using super = ValueMetadataBuilderBase<EnumMetadataVisitor<Impl>>;
3901+
bool HasUnfilledPayloadSize = false;
38743902

38753903
protected:
3876-
ConstantStructBuilder &B;
3904+
using ConstantBuilder = ConstantStructBuilder;
3905+
using NominalDecl = EnumDecl;
3906+
ConstantBuilder &B;
3907+
using super::asImpl;
38773908
using super::IGM;
38783909
using super::Target;
38793910

@@ -3894,8 +3925,12 @@ namespace {
38943925
return irgen::emitValueWitnessTable(IGM, type, false, relativeReference);
38953926
}
38963927

3928+
ConstantReference getValueWitnessTable(bool relativeReference) {
3929+
return emitValueWitnessTable(relativeReference);
3930+
}
3931+
38973932
void addValueWitnessTable() {
3898-
B.add(emitValueWitnessTable(/*relative*/ false).getValue());
3933+
B.add(asImpl().getValueWitnessTable(false).getValue());
38993934
}
39003935

39013936
llvm::Constant *emitNominalTypeDescriptor() {
@@ -3904,8 +3939,12 @@ namespace {
39043939
return descriptor;
39053940
}
39063941

3942+
llvm::Constant *getNominalTypeDescriptor() {
3943+
return emitNominalTypeDescriptor();
3944+
}
3945+
39073946
void addNominalTypeDescriptor() {
3908-
B.add(emitNominalTypeDescriptor());
3947+
B.add(asImpl().getNominalTypeDescriptor());
39093948
}
39103949

39113950
void addGenericArgument(GenericRequirement requirement) {
@@ -3915,16 +3954,22 @@ namespace {
39153954
void addGenericWitnessTable(GenericRequirement requirement) {
39163955
llvm_unreachable("Concrete type metadata cannot have generic requirements");
39173956
}
3918-
};
39193957

3920-
class EnumMetadataBuilder
3921-
: public EnumMetadataBuilderBase<EnumMetadataBuilder> {
3922-
bool HasUnfilledPayloadSize = false;
3958+
bool hasTrailingFlags() {
3959+
return IGM.shouldPrespecializeGenericMetadata();
3960+
}
39233961

3924-
public:
3925-
EnumMetadataBuilder(IRGenModule &IGM, EnumDecl *theEnum,
3926-
ConstantStructBuilder &B)
3927-
: EnumMetadataBuilderBase(IGM, theEnum, B) {}
3962+
void addTrailingFlags() {
3963+
auto flags = asImpl().getTrailingFlags();
3964+
3965+
B.addInt(IGM.Int64Ty, flags.getOpaqueValue());
3966+
}
3967+
3968+
MetadataTrailingFlags getTrailingFlags() {
3969+
MetadataTrailingFlags flags;
3970+
3971+
return flags;
3972+
}
39283973

39293974
void addPayloadSize() {
39303975
auto payloadSize = getConstantPayloadSize(IGM, Target);
@@ -3940,6 +3985,27 @@ namespace {
39403985
bool canBeConstant() {
39413986
return !HasUnfilledPayloadSize;
39423987
}
3988+
};
3989+
3990+
class SpecializedGenericEnumMetadataBuilder
3991+
: public SpecializedGenericNominalMetadataBuilderBase<
3992+
EnumMetadataBuilderBase, SpecializedGenericEnumMetadataBuilder> {
3993+
3994+
using super = SpecializedGenericNominalMetadataBuilderBase<
3995+
EnumMetadataBuilderBase, SpecializedGenericEnumMetadataBuilder>;
3996+
3997+
public:
3998+
SpecializedGenericEnumMetadataBuilder(IRGenModule &IGM, CanType type,
3999+
EnumDecl &decl, ConstantBuilder &B)
4000+
: super(IGM, type, decl, B){};
4001+
};
4002+
4003+
class EnumMetadataBuilder
4004+
: public EnumMetadataBuilderBase<EnumMetadataBuilder> {
4005+
public:
4006+
EnumMetadataBuilder(IRGenModule &IGM, EnumDecl *theEnum,
4007+
ConstantStructBuilder &B)
4008+
: EnumMetadataBuilderBase(IGM, theEnum, B) {}
39434009

39444010
void createMetadataAccessFunction() {
39454011
createNonGenericMetadataAccessFunction(IGM, Target);
@@ -3990,6 +4056,16 @@ namespace {
39904056
return EnumContextDescriptorBuilder(IGM, Target, RequireMetadata).emit();
39914057
}
39924058

4059+
GenericMetadataPatternFlags getPatternFlags() {
4060+
auto flags = super::getPatternFlags();
4061+
4062+
if (IGM.shouldPrespecializeGenericMetadata()) {
4063+
flags.setHasTrailingFlags(true);
4064+
}
4065+
4066+
return flags;
4067+
}
4068+
39934069
ConstantReference emitValueWitnessTable(bool relativeReference) {
39944070
assert(relativeReference && "should only relative reference");
39954071
return getValueWitnessTableForGenericValueType(IGM, Target,
@@ -4033,6 +4109,26 @@ void irgen::emitEnumMetadata(IRGenModule &IGM, EnumDecl *theEnum) {
40334109
init.finishAndCreateFuture());
40344110
}
40354111

4112+
void irgen::emitSpecializedGenericEnumMetadata(IRGenModule &IGM, CanType type,
4113+
EnumDecl &decl) {
4114+
Type ty = type.getPointer();
4115+
auto &context = type->getNominalOrBoundGenericNominal()->getASTContext();
4116+
PrettyStackTraceType stackTraceRAII(
4117+
context, "emitting prespecialized metadata for", ty);
4118+
ConstantInitBuilder initBuilder(IGM);
4119+
auto init = initBuilder.beginStruct();
4120+
init.setPacked(true);
4121+
4122+
bool isPattern = false;
4123+
4124+
SpecializedGenericEnumMetadataBuilder builder(IGM, type, decl, init);
4125+
builder.layout();
4126+
4127+
bool canBeConstant = builder.canBeConstant();
4128+
IGM.defineTypeMetadata(type, isPattern, canBeConstant,
4129+
init.finishAndCreateFuture());
4130+
}
4131+
40364132
llvm::Value *IRGenFunction::emitObjCSelectorRefLoad(StringRef selector) {
40374133
llvm::Constant *loadSelRef = IGM.getAddrOfObjCSelectorRef(selector);
40384134
llvm::Value *loadSel =

lib/IRGen/GenMeta.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,11 @@ namespace irgen {
8585
/// Emit the metadata associated with the given enum declaration.
8686
void emitEnumMetadata(IRGenModule &IGM, EnumDecl *theEnum);
8787

88-
void emitSpecializedGenericStructMetadata(IRGenModule &IGM, CanType type);
88+
void emitSpecializedGenericStructMetadata(IRGenModule &IGM, CanType type,
89+
StructDecl &decl);
90+
91+
void emitSpecializedGenericEnumMetadata(IRGenModule &IGM, CanType type,
92+
EnumDecl &decl);
8993

9094
/// Get what will be the index into the generic type argument array at the end
9195
/// of a nominal type's metadata.

stdlib/public/runtime/Metadata.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5223,6 +5223,8 @@ template <>
52235223
bool Metadata::isCanonicalStaticallySpecializedGenericMetadata() const {
52245224
if (auto *metadata = dyn_cast<StructMetadata>(this))
52255225
return metadata->isCanonicalStaticallySpecializedGenericMetadata();
5226+
if (auto *metadata = dyn_cast<EnumMetadata>(this))
5227+
return metadata->isCanonicalStaticallySpecializedGenericMetadata();
52265228

52275229
return false;
52285230
}

0 commit comments

Comments
 (0)