Skip to content

Commit 7068141

Browse files
committed
[IRGen] Emit prespecialized metadata records.
Prespecialized records contain direct references to the generic arguments and protocol witnesses with which it is specialized for now. Both prespecialized records and the records that are specialized at runtime gain a trailing pointer-sized flagset. For now, the flags in it include whether the record was prespecialized and whether it was known to be canonical at compile time (which is true for prespecialized records within the module which defines the type whose metadata is specialized since in those cases the metadata accessor can be modified). rdar://problem/56960307
1 parent d9205fa commit 7068141

File tree

4 files changed

+170
-8
lines changed

4 files changed

+170
-8
lines changed

lib/IRGen/GenMeta.cpp

Lines changed: 146 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@
1818
#include "swift/ABI/TypeIdentity.h"
1919
#include "swift/AST/ASTContext.h"
2020
#include "swift/AST/ASTMangler.h"
21+
#include "swift/AST/Attr.h"
2122
#include "swift/AST/CanTypeVisitor.h"
2223
#include "swift/AST/Decl.h"
23-
#include "swift/AST/Attr.h"
24+
#include "swift/AST/GenericEnvironment.h"
2425
#include "swift/AST/IRGenOptions.h"
2526
#include "swift/AST/PrettyStackTrace.h"
2627
#include "swift/AST/SubstitutionMap.h"
@@ -31,13 +32,13 @@
3132
#include "swift/SIL/SILModule.h"
3233
#include "swift/SIL/TypeLowering.h"
3334
#include "swift/Strings.h"
35+
#include "clang/AST/Decl.h"
36+
#include "clang/AST/DeclObjC.h"
3437
#include "llvm/ADT/SmallString.h"
3538
#include "llvm/IR/DerivedTypes.h"
3639
#include "llvm/IR/Function.h"
3740
#include "llvm/IR/GlobalVariable.h"
3841
#include "llvm/IR/Module.h"
39-
#include "clang/AST/Decl.h"
40-
#include "clang/AST/DeclObjC.h"
4142

4243
#include "Address.h"
4344
#include "Callee.h"
@@ -3474,23 +3475,31 @@ namespace {
34743475
return descriptor;
34753476
}
34763477

3478+
llvm::Constant *getNominalTypeDescriptor() {
3479+
return emitNominalTypeDescriptor();
3480+
}
3481+
34773482
void addNominalTypeDescriptor() {
3478-
B.add(emitNominalTypeDescriptor());
3483+
B.add(asImpl().getNominalTypeDescriptor());
34793484
}
34803485

34813486
ConstantReference emitValueWitnessTable(bool relativeReference) {
34823487
auto type = this->Target->getDeclaredType()->getCanonicalType();
34833488
return irgen::emitValueWitnessTable(IGM, type, false, relativeReference);
34843489
}
34853490

3491+
ConstantReference getValueWitnessTable(bool relativeReference) {
3492+
return emitValueWitnessTable(relativeReference);
3493+
}
3494+
34863495
void addValueWitnessTable() {
3487-
B.add(emitValueWitnessTable(false).getValue());
3496+
B.add(asImpl().getValueWitnessTable(false).getValue());
34883497
}
34893498

34903499
void addFieldOffset(VarDecl *var) {
34913500
assert(var->hasStorage() &&
34923501
"storing field offset for computed property?!");
3493-
SILType structType = getLoweredType();
3502+
SILType structType = asImpl().getLoweredType();
34943503

34953504
llvm::Constant *offset =
34963505
emitPhysicalStructMemberFixedOffset(IGM, structType, var);
@@ -3515,6 +3524,22 @@ namespace {
35153524
void addGenericWitnessTable(GenericRequirement requirement) {
35163525
llvm_unreachable("Concrete type metadata cannot have generic requirements");
35173526
}
3527+
3528+
bool hasTrailingFlags() {
3529+
return IGM.shouldPrespecializeGenericMetadata();
3530+
}
3531+
3532+
void addTrailingFlags() {
3533+
auto flags = asImpl().getTrailingFlags();
3534+
3535+
B.addInt(IGM.Int64Ty, flags.getOpaqueValue());
3536+
}
3537+
3538+
MetadataTrailingFlags getTrailingFlags() {
3539+
MetadataTrailingFlags flags;
3540+
3541+
return flags;
3542+
}
35183543
};
35193544

35203545
class StructMetadataBuilder :
@@ -3587,6 +3612,16 @@ namespace {
35873612
return StructContextDescriptorBuilder(IGM, Target, RequireMetadata).emit();
35883613
}
35893614

3615+
GenericMetadataPatternFlags getPatternFlags() {
3616+
auto flags = super::getPatternFlags();
3617+
3618+
if (IGM.shouldPrespecializeGenericMetadata()) {
3619+
flags.setHasTrailingFlags(true);
3620+
}
3621+
3622+
return flags;
3623+
}
3624+
35903625
ConstantReference emitValueWitnessTable(bool relativeReference) {
35913626
assert(relativeReference && "should only relative reference");
35923627
return getValueWitnessTableForGenericValueType(IGM, Target,
@@ -3646,10 +3681,96 @@ namespace {
36463681
vectorSize };
36473682
}
36483683

3684+
void addTrailingFlags() { this->B.addInt(IGM.Int64Ty, 0); }
3685+
36493686
bool hasCompletionFunction() {
36503687
return !isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType()));
36513688
}
36523689
};
3690+
3691+
class SpecializedGenericStructMetadataBuilder
3692+
: public StructMetadataBuilderBase<
3693+
SpecializedGenericStructMetadataBuilder> {
3694+
using super =
3695+
StructMetadataBuilderBase<SpecializedGenericStructMetadataBuilder>;
3696+
CanType type;
3697+
bool HasUnfilledFieldOffset = false;
3698+
3699+
protected:
3700+
using super::asImpl;
3701+
using super::getLoweredType;
3702+
using super::IGM;
3703+
using super::Target;
3704+
3705+
public:
3706+
SpecializedGenericStructMetadataBuilder(IRGenModule &IGM, CanType type,
3707+
StructDecl &decl,
3708+
ConstantStructBuilder &B)
3709+
: super(IGM, &decl, B), type(type) {}
3710+
3711+
void noteStartOfTypeSpecificMembers() {}
3712+
3713+
llvm::Constant *getNominalTypeDescriptor() {
3714+
return IGM.getAddrOfTypeContextDescriptor(Target, RequireMetadata);
3715+
}
3716+
3717+
SILType getLoweredType() { return SILType::getPrimitiveObjectType(type); }
3718+
3719+
ConstantReference getValueWitnessTable(bool relativeReference) {
3720+
auto type = this->Target->getDeclaredType()->getCanonicalType();
3721+
return ConstantReference(IGM.getAddrOfEffectiveValueWitnessTable(type),
3722+
irgen::ConstantReference::Direct);
3723+
}
3724+
3725+
void addGenericArgument(GenericRequirement requirement) {
3726+
auto t = requirement.TypeParameter.subst(genericSubstitutions());
3727+
ConstantReference ref = IGM.getAddrOfTypeMetadata(
3728+
CanType(t), SymbolReferenceKind::Relative_Direct);
3729+
B.add(ref.getDirectValue());
3730+
}
3731+
3732+
void addGenericWitnessTable(GenericRequirement requirement) {
3733+
auto conformance = genericSubstitutions().lookupConformance(
3734+
requirement.TypeParameter->getCanonicalType(), requirement.Protocol);
3735+
ProtocolConformance *concreteConformance = conformance.getConcrete();
3736+
3737+
llvm::Constant *addr;
3738+
3739+
Type argument = requirement.TypeParameter.subst(genericSubstitutions());
3740+
auto argumentNominal = argument->getAnyNominal();
3741+
if (argumentNominal && argumentNominal->isGenericContext()) {
3742+
// TODO: Statically specialize the witness table pattern for t's
3743+
// conformance.
3744+
llvm_unreachable("Statically specializing metadata at generic types is "
3745+
"not supported.");
3746+
} else {
3747+
RootProtocolConformance *rootConformance =
3748+
concreteConformance->getRootConformance();
3749+
addr = IGM.getAddrOfWitnessTable(rootConformance);
3750+
}
3751+
3752+
B.add(addr);
3753+
}
3754+
3755+
SubstitutionMap genericSubstitutions() {
3756+
return type->getContextSubstitutionMap(IGM.getSwiftModule(),
3757+
type->getAnyNominal());
3758+
}
3759+
3760+
MetadataTrailingFlags getTrailingFlags() {
3761+
MetadataTrailingFlags flags = super::getTrailingFlags();
3762+
3763+
flags.setIsStaticSpecialization(true);
3764+
flags.setIsCanonicalStaticSpecialization(true);
3765+
3766+
return flags;
3767+
}
3768+
3769+
void flagUnfilledFieldOffset() { HasUnfilledFieldOffset = true; }
3770+
3771+
bool canBeConstant() { return !HasUnfilledFieldOffset; }
3772+
};
3773+
36533774
} // end anonymous namespace
36543775

36553776
/// Emit the type metadata or metadata template for a struct.
@@ -3683,9 +3804,26 @@ void irgen::emitStructMetadata(IRGenModule &IGM, StructDecl *structDecl) {
36833804
init.finishAndCreateFuture());
36843805
}
36853806

3686-
/// Emit the type metadata or metadata template for a struct.
36873807
void irgen::emitSpecializedGenericStructMetadata(IRGenModule &IGM,
3688-
CanType type) {}
3808+
CanType type) {
3809+
Type ty = type.getPointer();
3810+
auto &context = type->getNominalOrBoundGenericNominal()->getASTContext();
3811+
PrettyStackTraceType stackTraceRAII(
3812+
context, "emitting prespecialized metadata for", ty);
3813+
ConstantInitBuilder initBuilder(IGM);
3814+
auto init = initBuilder.beginStruct();
3815+
init.setPacked(true);
3816+
3817+
bool isPattern = false;
3818+
3819+
auto &decl = *type.getStructOrBoundGenericStruct();
3820+
SpecializedGenericStructMetadataBuilder builder(IGM, type, decl, init);
3821+
builder.layout();
3822+
3823+
bool canBeConstant = builder.canBeConstant();
3824+
IGM.defineTypeMetadata(type, isPattern, canBeConstant,
3825+
init.finishAndCreateFuture());
3826+
}
36893827

36903828
// Enums
36913829

lib/IRGen/GenValueWitness.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,16 @@ getAddrOfKnownValueWitnessTable(IRGenModule &IGM, CanType type,
10231023
return {};
10241024
}
10251025

1026+
llvm::Constant *
1027+
IRGenModule::getAddrOfEffectiveValueWitnessTable(CanType concreteType,
1028+
ConstantInit init) {
1029+
if (auto known =
1030+
getAddrOfKnownValueWitnessTable(*this, concreteType, false)) {
1031+
return known.getValue();
1032+
}
1033+
return getAddrOfValueWitnessTable(concreteType);
1034+
}
1035+
10261036
/// Emit a value-witness table for the given type.
10271037
ConstantReference irgen::emitValueWitnessTable(IRGenModule &IGM,
10281038
CanType abstractType,

lib/IRGen/IRGenModule.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,6 +1300,9 @@ private: \
13001300
ForDefinition_t forDefinition);
13011301
llvm::Constant *getAddrOfValueWitnessTable(CanType concreteType,
13021302
ConstantInit init = ConstantInit());
1303+
llvm::Constant *
1304+
getAddrOfEffectiveValueWitnessTable(CanType concreteType,
1305+
ConstantInit init = ConstantInit());
13031306
Optional<llvm::Function*> getAddrOfIVarInitDestroy(ClassDecl *cd,
13041307
bool isDestroyer,
13051308
bool isForeign,

lib/IRGen/StructMetadataVisitor.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define SWIFT_IRGEN_STRUCTMETADATALAYOUT_H
1919

2020
#include "NominalMetadataVisitor.h"
21+
#include "swift/AST/IRGenOptions.h"
2122

2223
namespace swift {
2324
namespace irgen {
@@ -61,13 +62,21 @@ template <class Impl> class StructMetadataVisitor
6162
asImpl().addFieldOffset(prop);
6263

6364
asImpl().noteEndOfFieldOffsets();
65+
66+
if (asImpl().hasTrailingFlags())
67+
asImpl().addTrailingFlags();
6468
}
6569

6670
// Note the start of the field offset vector.
6771
void noteStartOfFieldOffsets() {}
6872

6973
// Note the end of the field offset vector.
7074
void noteEndOfFieldOffsets() {}
75+
76+
bool hasTrailingFlags() {
77+
return Target->isGenericContext() &&
78+
IGM.shouldPrespecializeGenericMetadata();
79+
}
7180
};
7281

7382
/// An "implementation" of StructMetadataVisitor that just scans through
@@ -95,6 +104,8 @@ class StructMetadataScanner : public StructMetadataVisitor<Impl> {
95104
NextOffset = NextOffset.roundUpToAlignment(super::IGM.getPointerAlignment());
96105
}
97106

107+
void addTrailingFlags() { addPointer(); }
108+
98109
private:
99110
void addPointer() {
100111
NextOffset += super::IGM.getPointerSize();

0 commit comments

Comments
 (0)