Skip to content

[IRGen] Narrow the “requires instantiation” bit for conformances. #20034

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2009,7 +2009,11 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(SILFunction *f,

static llvm::GlobalVariable *createGOTEquivalent(IRGenModule &IGM,
llvm::Constant *global,
StringRef globalName) {
LinkEntity entity) {
// Determine the name of this entity.
llvm::SmallString<64> globalName;
entity.mangle(globalName);

if (IGM.Triple.getObjectFormat() == llvm::Triple::COFF) {
if (cast<llvm::GlobalValue>(global)->hasDLLImportStorageClass()) {
llvm::GlobalVariable *GV =
Expand Down Expand Up @@ -2178,7 +2182,7 @@ IRGenModule::getAddrOfLLVMVariable(LinkEntity entity,

// Make a new GOT equivalent referring to the new variable with its
// definition type.
auto newGOTEquiv = createGOTEquivalent(*this, var, var->getName());
auto newGOTEquiv = createGOTEquivalent(*this, var, entity);
auto castGOTEquiv = llvm::ConstantExpr::getBitCast(newGOTEquiv,
existingGOTEquiv->getType());
existingGOTEquiv->replaceAllUsesWith(castGOTEquiv);
Expand Down Expand Up @@ -2256,9 +2260,7 @@ IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity,
auto global = cast<llvm::GlobalValue>(entry);
// Use it as the initializer for an anonymous constant. LLVM can treat this as
// equivalent to the global's GOT entry.
llvm::SmallString<64> name;
entity.mangle(name);
auto gotEquivalent = createGOTEquivalent(*this, global, name);
auto gotEquivalent = createGOTEquivalent(*this, global, entity);
gotEntry = gotEquivalent;
return {gotEquivalent, ConstantReference::Indirect};
};
Expand Down
44 changes: 29 additions & 15 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,31 @@ static bool isResilientConformance(const NormalProtocolConformance *conformance)
return true;
}

/// Whether this protocol conformance has a dependent type witness.
static bool hasDependentTypeWitness(
const NormalProtocolConformance *conformance) {
auto DC = conformance->getDeclContext();
// If the conforming type isn't dependent, the below check is never true.
if (!DC->isGenericContext())
return false;

// Check whether any of the associated types are dependent.
if (conformance->forEachTypeWitness(nullptr,
[&](AssociatedTypeDecl *requirement, Type type,
TypeDecl *explicitDecl) -> bool {
// Skip associated types that don't have witness table entries.
if (!requirement->getOverriddenDecls().empty())
return false;

// RESILIENCE: this could be an opaque conformance
return type->hasTypeParameter();
})) {
return true;
}

return false;
}

/// Is there anything about the given conformance that requires witness
/// tables to be dependently-generated?
bool irgen::isDependentConformance(const NormalProtocolConformance *conformance) {
Expand All @@ -984,20 +1009,8 @@ bool irgen::isDependentConformance(const NormalProtocolConformance *conformance)
return true;
}

auto DC = conformance->getDeclContext();
// If the conforming type isn't dependent, the below check is never true.
if (!DC->isGenericContext())
return false;

// Check whether any of the associated types are dependent.
if (conformance->forEachTypeWitness(nullptr,
[&](AssociatedTypeDecl *requirement, Type type,
TypeDecl *explicitDecl) -> bool {
// RESILIENCE: this could be an opaque conformance
return type->hasTypeParameter();
})) {
if (hasDependentTypeWitness(conformance))
return true;
}

// Check if there are any conditional conformances. Other forms of conditional
// requirements don't exist in the witness table.
Expand Down Expand Up @@ -2184,7 +2197,7 @@ namespace {
// WitnessTablePrivateSizeInWordsAndRequiresInstantiation
B.addInt(IGM.Int16Ty,
(Description.witnessTablePrivateSize << 1) |
Description.requiresSpecialization);
Description.hasDependentAssociatedTypeWitnesses);
// RelativePointer<WitnessTable>
B.addRelativeAddress(Description.pattern);
// Instantiation function
Expand Down Expand Up @@ -2413,7 +2426,8 @@ void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) {
ConformanceDescription description(conf, wt, global,
wtableBuilder.getTableSize(),
wtableBuilder.getTablePrivateSize(),
wtableBuilder.requiresSpecialization());
wtableBuilder.requiresSpecialization(),
hasDependentTypeWitness(conf));

// Build the instantiation function, we if need one.
description.instantiationFn = wtableBuilder.buildInstantiationFunction();
Expand Down
11 changes: 9 additions & 2 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,9 @@ struct ConformanceDescription {
/// Whether this witness table requires runtime specialization.
const unsigned requiresSpecialization : 1;

/// Whether this witness table contains dependent associated type witnesses.
const unsigned hasDependentAssociatedTypeWitnesses : 1;

/// The instantiation function, to be run at the end of witness table
/// instantiation.
llvm::Constant *instantiationFn = nullptr;
Expand All @@ -482,11 +485,15 @@ struct ConformanceDescription {
llvm::Constant *pattern,
uint16_t witnessTableSize,
uint16_t witnessTablePrivateSize,
bool requiresSpecialization)
bool requiresSpecialization,
bool hasDependentAssociatedTypeWitnesses)
: conformance(conformance), wtable(wtable), pattern(pattern),
witnessTableSize(witnessTableSize),
witnessTablePrivateSize(witnessTablePrivateSize),
requiresSpecialization(requiresSpecialization) { }
requiresSpecialization(requiresSpecialization),
hasDependentAssociatedTypeWitnesses(hasDependentAssociatedTypeWitnesses)
{
}
};

/// IRGenModule - Primary class for emitting IR for global declarations.
Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/associated_type_witness.swift
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ struct UsesVoid : HasSimpleAssoc {
// Protocol conformance descriptor for GenericComputed : DerivedFromSimpleAssoc.
// GLOBAL-LABEL: @"$s23associated_type_witness15GenericComputedVyxGAA22DerivedFromSimpleAssocAAMc" = hidden constant
// GLOBAL-SAME: i16 2,
// GLOBAL-SAME: i16 1,
// GLOBAL-SAME: i16 0,

// Relative reference to witness table template
// GLOBAL-SAME: i32 trunc (i64 sub (i64 ptrtoint ([2 x i8*]* @"$s23associated_type_witness15GenericComputedVyxGAA22DerivedFromSimpleAssocAAWp" to i64
Expand Down
4 changes: 4 additions & 0 deletions test/IRGen/protocol_conformance_records.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ extension Int : OtherResilientProtocol { }
// CHECK-SAME: @"$s28protocol_conformance_records9DependentVyxGAA9AssociateAAWa"
// -- flags
// CHECK-SAME: i32 1
// -- number of words in witness table
// CHECK-SAME: i16 2,
// -- number of private words in witness table + bit for "needs instantiation"
// CHECK-SAME: i16 1
// CHECK-SAME: }
extension Dependent : Associate {
public typealias X = (T, T)
Expand Down
8 changes: 4 additions & 4 deletions test/IRGen/protocol_resilience.sil
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ protocol InternalProtocol {
// -- number of witness table entries
// CHECK-SAME: i16 1,

// -- size of private area + 'needs instantiation' bit
// CHECK-SAME: i16 1,
// -- size of private area + 'requires instantiation' bit (not set)
// CHECK-SAME: i16 0,

// -- the template
// CHECK-SAME: @"$s19protocol_resilience23ResilientConformingTypeV010resilient_A005OtherC8ProtocolAAWp"
Expand Down Expand Up @@ -139,8 +139,8 @@ protocol InternalProtocol {
// -- number of witness table entries
// CHECK-SAME: i16 1,

// -- size of private area + 'needs instantiation' bit
// CHECK-SAME: i16 1,
// -- size of private area + 'requires instantiation' bit (not set)
// CHECK-SAME: i16 0,

// -- the template
// CHECK-SAME: @"$s19protocol_resilience24ConformsWithRequirementsV010resilient_A008ProtocoldE0AAWp"
Expand Down
6 changes: 6 additions & 0 deletions test/IRGen/protocol_resilience_descriptors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ public protocol P { }
public struct ConditionallyConforms<Element> { }
public struct Y { }

// CHECK-USAGE-LABEL: @"$s31protocol_resilience_descriptors1YV010resilient_A022OtherResilientProtocolAAMc" =
// CHECK-USAGE-SAME: i32 131073,
// CHECK-USAGE-SAME: i16 1,
// CHECK-USAGE-SAME: i16 0
extension Y: OtherResilientProtocol { }

// CHECK-USAGE: @"$s31protocol_resilience_descriptors29ConformsWithAssocRequirementsV010resilient_A008ProtocoleF12TypeDefaultsAAMc" =
// CHECK-USAGE-SAME: $s18resilient_protocol29ProtocolWithAssocTypeDefaultsP2T2AC_AA014OtherResilientC0Tn
// CHECK-USAGE-SAME: $s31protocol_resilience_descriptors29ConformsWithAssocRequirementsV010resilient_A008ProtocoleF12TypeDefaultsAA2T2AdEP_AD014OtherResilientI0PWT
Expand Down