Skip to content

Commit befffd9

Browse files
authored
Merge pull request #26584 from jckarter/prefab-value-witness-in-generic-pattern
IRGen: Use known value witnesses in generic metadata patterns.
2 parents c43eb9b + b5f36f7 commit befffd9

File tree

4 files changed

+65
-49
lines changed

4 files changed

+65
-49
lines changed

lib/IRGen/GenMeta.cpp

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2358,7 +2358,8 @@ template <class Impl, class DeclType>
23582358
}
23592359

23602360
void addValueWitnessTable() {
2361-
auto table = asImpl().emitValueWitnessTable();
2361+
ConstantReference table =
2362+
asImpl().emitValueWitnessTable(/*relative*/ true);
23622363
B.addRelativeAddress(table);
23632364
}
23642365

@@ -3455,13 +3456,13 @@ namespace {
34553456
B.add(emitNominalTypeDescriptor());
34563457
}
34573458

3458-
llvm::Constant *emitValueWitnessTable() {
3459+
ConstantReference emitValueWitnessTable(bool relativeReference) {
34593460
auto type = this->Target->getDeclaredType()->getCanonicalType();
3460-
return irgen::emitValueWitnessTable(IGM, type, false);
3461+
return irgen::emitValueWitnessTable(IGM, type, false, relativeReference);
34613462
}
34623463

34633464
void addValueWitnessTable() {
3464-
B.add(emitValueWitnessTable());
3465+
B.add(emitValueWitnessTable(false).getValue());
34653466
}
34663467

34673468
void addFieldOffset(VarDecl *var) {
@@ -3517,18 +3518,18 @@ namespace {
35173518
}
35183519
};
35193520

3520-
/// Emit a value witness table for a fixed-layout generic type, or a null
3521-
/// placeholder if the value witness table is dependent on generic parameters.
3522-
/// Returns nullptr if the value witness table is dependent.
3523-
static llvm::Constant *
3521+
/// Emit a value witness table for a fixed-layout generic type, or a template
3522+
/// if the value witness table is dependent on generic parameters.
3523+
static ConstantReference
35243524
getValueWitnessTableForGenericValueType(IRGenModule &IGM,
35253525
NominalTypeDecl *decl,
35263526
bool &dependent) {
35273527
CanType unboundType
35283528
= decl->getDeclaredType()->getCanonicalType();
35293529

35303530
dependent = hasDependentValueWitnessTable(IGM, unboundType);
3531-
return emitValueWitnessTable(IGM, unboundType, dependent);
3531+
return emitValueWitnessTable(IGM, unboundType, dependent,
3532+
/*relative reference*/ true);
35323533
}
35333534

35343535
/// A builder for metadata templates.
@@ -3564,7 +3565,8 @@ namespace {
35643565
return StructContextDescriptorBuilder(IGM, Target, RequireMetadata).emit();
35653566
}
35663567

3567-
llvm::Constant *emitValueWitnessTable() {
3568+
ConstantReference emitValueWitnessTable(bool relativeReference) {
3569+
assert(relativeReference && "should only relative reference");
35683570
return getValueWitnessTableForGenericValueType(IGM, Target,
35693571
HasDependentVWT);
35703572
}
@@ -3697,13 +3699,13 @@ namespace {
36973699
B.addInt(IGM.MetadataKindTy, unsigned(getMetadataKind(Target)));
36983700
}
36993701

3700-
llvm::Constant *emitValueWitnessTable() {
3702+
ConstantReference emitValueWitnessTable(bool relativeReference) {
37013703
auto type = Target->getDeclaredType()->getCanonicalType();
3702-
return irgen::emitValueWitnessTable(IGM, type, false);
3704+
return irgen::emitValueWitnessTable(IGM, type, false, relativeReference);
37033705
}
37043706

37053707
void addValueWitnessTable() {
3706-
B.add(emitValueWitnessTable());
3708+
B.add(emitValueWitnessTable(/*relative*/ false).getValue());
37073709
}
37083710

37093711
llvm::Constant *emitNominalTypeDescriptor() {
@@ -3798,7 +3800,8 @@ namespace {
37983800
return EnumContextDescriptorBuilder(IGM, Target, RequireMetadata).emit();
37993801
}
38003802

3801-
llvm::Constant *emitValueWitnessTable() {
3803+
ConstantReference emitValueWitnessTable(bool relativeReference) {
3804+
assert(relativeReference && "should only relative reference");
38023805
return getValueWitnessTableForGenericValueType(IGM, Target,
38033806
HasDependentVWT);
38043807
}
@@ -4054,7 +4057,7 @@ namespace {
40544057
}
40554058

40564059
void addValueWitnessTable() {
4057-
B.add(emitValueWitnessTable());
4060+
B.add(emitValueWitnessTable(/*relative*/ false).getValue());
40584061
}
40594062

40604063
void flagUnfilledFieldOffset() {
@@ -4081,7 +4084,7 @@ namespace {
40814084
}
40824085

40834086
void addValueWitnessTable() {
4084-
B.add(emitValueWitnessTable());
4087+
B.add(emitValueWitnessTable(/*relative*/ false).getValue());
40854088
}
40864089

40874090
void addPayloadSize() const {

lib/IRGen/GenValueWitness.cpp

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -927,25 +927,21 @@ static constexpr uint64_t sizeAndAlignment(Size size, Alignment alignment) {
927927
/// Return a reference to a known value witness table from the runtime
928928
/// that's suitable for the given type, if there is one, or return null
929929
/// if we should emit a new one.
930-
static llvm::Constant *
931-
getAddrOfKnownValueWitnessTable(IRGenModule &IGM, CanType type) {
930+
static ConstantReference
931+
getAddrOfKnownValueWitnessTable(IRGenModule &IGM, CanType type,
932+
bool relativeReference) {
932933
// Native PE binaries shouldn't reference data symbols across DLLs, so disable
933-
// this on Windows.
934-
if (IGM.useDllStorage())
935-
return nullptr;
934+
// this on Windows, unless we're forming a relative indirectable reference.
935+
if (IGM.useDllStorage() && !relativeReference)
936+
return {};
936937

937938
if (auto nom = type->getAnyNominal()) {
938-
// TODO: Generic metadata patterns relative-reference their VWT, which won't
939-
// work if the VWT is in a different module without supporting indirection
940-
// through the GOT.
941-
if (nom->isGenericContext())
942-
return nullptr;
943939
// TODO: Non-C enums have extra inhabitants and also need additional value
944940
// witnesses for their tag manipulation (except when they're empty, in
945941
// which case values never exist to witness).
946942
if (auto enumDecl = dyn_cast<EnumDecl>(nom))
947943
if (!enumDecl->isObjC() && !type->isUninhabited())
948-
return nullptr;
944+
return {};
949945
}
950946

951947
auto &C = IGM.Context;
@@ -954,20 +950,19 @@ getAddrOfKnownValueWitnessTable(IRGenModule &IGM, CanType type) {
954950

955951
auto &ti = IGM.getTypeInfoForUnlowered(AbstractionPattern::getOpaque(), type);
956952

957-
// Empty types can use empty tuple witnesses.
958-
if (ti.isKnownEmpty(ResilienceExpansion::Maximal))
959-
return IGM.getAddrOfValueWitnessTable(TupleType::getEmpty(C));
960-
961953
// We only have witnesses for fixed type info.
962954
auto *fixedTI = dyn_cast<FixedTypeInfo>(&ti);
963955
if (!fixedTI)
964-
return nullptr;
965-
956+
return {};
957+
966958
CanType witnessSurrogate;
959+
ReferenceCounting refCounting;
967960

961+
// Empty types can use empty tuple witnesses.
962+
if (ti.isKnownEmpty(ResilienceExpansion::Maximal)) {
963+
witnessSurrogate = TupleType::getEmpty(C);
968964
// Handle common POD type layouts.
969-
ReferenceCounting refCounting;
970-
if (fixedTI->isPOD(ResilienceExpansion::Maximal)
965+
} else if (fixedTI->isPOD(ResilienceExpansion::Maximal)
971966
&& fixedTI->getFixedExtraInhabitantCount(IGM) == 0) {
972967
// Reuse one of the integer witnesses if applicable.
973968
switch (sizeAndAlignment(fixedTI->getFixedSize(),
@@ -1015,26 +1010,32 @@ getAddrOfKnownValueWitnessTable(IRGenModule &IGM, CanType type) {
10151010
break;
10161011
}
10171012
}
1018-
1019-
if (witnessSurrogate)
1020-
return IGM.getAddrOfValueWitnessTable(witnessSurrogate);
1021-
return nullptr;
1013+
1014+
if (witnessSurrogate) {
1015+
if (relativeReference) {
1016+
return IGM.getAddrOfLLVMVariableOrGOTEquivalent(
1017+
LinkEntity::forValueWitnessTable(witnessSurrogate));
1018+
} else {
1019+
return {IGM.getAddrOfValueWitnessTable(witnessSurrogate),
1020+
ConstantReference::Direct};
1021+
}
1022+
}
1023+
return {};
10221024
}
10231025

1024-
/// Emit a value-witness table for the given type, which is assumed to
1025-
/// be non-dependent.
1026-
llvm::Constant *irgen::emitValueWitnessTable(IRGenModule &IGM,
1026+
/// Emit a value-witness table for the given type.
1027+
ConstantReference irgen::emitValueWitnessTable(IRGenModule &IGM,
10271028
CanType abstractType,
1028-
bool isPattern) {
1029+
bool isPattern,
1030+
bool relativeReference) {
10291031
// We shouldn't emit global value witness tables for generic type instances.
10301032
assert(!isa<BoundGenericType>(abstractType) &&
10311033
"emitting VWT for generic instance");
10321034

10331035
// See if we can use a prefab witness table from the runtime.
1034-
// Note that we can't do this on Windows since the PE loader does not support
1035-
// cross-DLL pointers in data.
10361036
if (!isPattern) {
1037-
if (auto known = getAddrOfKnownValueWitnessTable(IGM, abstractType)) {
1037+
if (auto known = getAddrOfKnownValueWitnessTable(IGM, abstractType,
1038+
relativeReference)) {
10381039
return known;
10391040
}
10401041
}
@@ -1061,7 +1062,8 @@ llvm::Constant *irgen::emitValueWitnessTable(IRGenModule &IGM,
10611062
auto global = cast<llvm::GlobalVariable>(addr);
10621063
global->setConstant(canBeConstant);
10631064

1064-
return llvm::ConstantExpr::getBitCast(global, IGM.WitnessTablePtrTy);
1065+
return {llvm::ConstantExpr::getBitCast(global, IGM.WitnessTablePtrTy),
1066+
ConstantReference::Direct};
10651067
}
10661068

10671069
llvm::Constant *IRGenModule::emitFixedTypeLayout(CanType t,

lib/IRGen/GenValueWitness.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ namespace swift {
3131
namespace irgen {
3232
class ConstantStructBuilder;
3333
class IRGenModule;
34+
class ConstantReference;
3435

3536
/// True if a type has a generic-parameter-dependent value witness table.
3637
/// Currently, this is true if the size and/or alignment of the type is
@@ -42,8 +43,9 @@ namespace irgen {
4243
/// \param isPattern - true if the table just serves as an instantiation
4344
/// pattern and does not need to be modifiable in-place (if the type
4445
/// does not have static layout for some reason)
45-
llvm::Constant *emitValueWitnessTable(IRGenModule &IGM, CanType type,
46-
bool isPattern);
46+
ConstantReference emitValueWitnessTable(IRGenModule &IGM, CanType type,
47+
bool isPattern,
48+
bool relativeReference);
4749
}
4850
}
4951

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %s
2+
3+
// CHECK-LABEL: @"$s36generic_metadata_fixed_known_vwtable6StroctVMP" =
4+
// CHECK-SAME: $sytWV
5+
struct Stroct<T> {}
6+
7+
// CHECK-LABEL: @"$s36generic_metadata_fixed_known_vwtable4EnomOMP" =
8+
// CHECK-SAME: $sytWV
9+
enum Enom<T> {}

0 commit comments

Comments
 (0)