Skip to content

SIL: Generate external key path references with local candidate components. #17802

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
112 changes: 48 additions & 64 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -2279,7 +2279,6 @@ class KeyPathPatternComponent {
StoredProperty,
GettableProperty,
SettableProperty,
External,
OptionalChain,
OptionalForce,
OptionalWrap,
Expand All @@ -2298,7 +2297,6 @@ class KeyPathPatternComponent {
enum PackedKind: unsigned {
PackedStored,
PackedComputed,
PackedExternal,
Unpacked,
};

Expand All @@ -2311,8 +2309,6 @@ class KeyPathPatternComponent {
case Kind::GettableProperty:
case Kind::SettableProperty:
return PackedComputed;
case Kind::External:
return PackedExternal;
case Kind::OptionalChain:
case Kind::OptionalForce:
case Kind::OptionalWrap:
Expand All @@ -2323,23 +2319,18 @@ class KeyPathPatternComponent {
// Value is the VarDecl* for StoredProperty, the SILFunction* of the
// Getter for computed properties, or the Kind for other kinds
llvm::PointerIntPair<void *, KindPackingBits, unsigned> ValueAndKind;
union {
// Valid if Kind == GettableProperty || Kind == SettableProperty
struct {
llvm::PointerIntPair<SILFunction *, 2,
ComputedPropertyId::KindType> SetterAndIdKind;
ComputedPropertyId::ValueType IdValue;
} Computed;
// Valid if Kind == External
SubstitutionMap ExternalSubstitutions;
};
llvm::PointerIntPair<SILFunction *, 2,
ComputedPropertyId::KindType> SetterAndIdKind;
ComputedPropertyId::ValueType IdValue;
ArrayRef<Index> Indices;
struct {
SILFunction *Equal;
SILFunction *Hash;
} IndexEquality;
CanType ComponentType;

AbstractStorageDecl *ExternalStorage;
SubstitutionMap ExternalSubstitutions;

/// Constructor for stored components
KeyPathPatternComponent(VarDecl *storedProp,
CanType ComponentType)
Expand All @@ -2353,26 +2344,18 @@ class KeyPathPatternComponent {
ArrayRef<Index> indices,
SILFunction *indicesEqual,
SILFunction *indicesHash,
AbstractStorageDecl *externalStorage,
SubstitutionMap externalSubstitutions,
CanType ComponentType)
: ValueAndKind(getter, PackedComputed),
Computed{{setter, id.Kind}, {id.Value}},
SetterAndIdKind{setter, id.Kind},
IdValue{id.Value},
Indices(indices),
IndexEquality{indicesEqual, indicesHash},
ComponentType(ComponentType) {
}

/// Constructor for external components
KeyPathPatternComponent(AbstractStorageDecl *externalStorage,
SubstitutionMap substitutions,
ArrayRef<Index> indices,
SILFunction *indicesEqual,
SILFunction *indicesHash,
CanType componentType)
: ValueAndKind(externalStorage, PackedExternal),
ExternalSubstitutions(substitutions),
Indices(indices),
IndexEquality{indicesEqual, indicesHash},
ComponentType(componentType) {
ComponentType(ComponentType),
ExternalStorage(externalStorage),
ExternalSubstitutions(externalSubstitutions)
{
}

/// Constructor for optional components.
Expand All @@ -2396,10 +2379,8 @@ class KeyPathPatternComponent {
case PackedStored:
return Kind::StoredProperty;
case PackedComputed:
return Computed.SetterAndIdKind.getPointer()
return SetterAndIdKind.getPointer()
? Kind::SettableProperty : Kind::GettableProperty;
case PackedExternal:
return Kind::External;
case Unpacked:
return (Kind)((uintptr_t)ValueAndKind.getPointer() >> KindPackingBits);
}
Expand All @@ -2418,7 +2399,6 @@ class KeyPathPatternComponent {
case Kind::OptionalChain:
case Kind::OptionalForce:
case Kind::OptionalWrap:
case Kind::External:
llvm_unreachable("not a stored property");
}
llvm_unreachable("unhandled kind");
Expand All @@ -2430,12 +2410,11 @@ class KeyPathPatternComponent {
case Kind::OptionalChain:
case Kind::OptionalForce:
case Kind::OptionalWrap:
case Kind::External:
llvm_unreachable("not a computed property");
case Kind::GettableProperty:
case Kind::SettableProperty:
return ComputedPropertyId(Computed.IdValue,
Computed.SetterAndIdKind.getInt());
return ComputedPropertyId(IdValue,
SetterAndIdKind.getInt());
}
llvm_unreachable("unhandled kind");
}
Expand All @@ -2446,7 +2425,6 @@ class KeyPathPatternComponent {
case Kind::OptionalChain:
case Kind::OptionalForce:
case Kind::OptionalWrap:
case Kind::External:
llvm_unreachable("not a computed property");
case Kind::GettableProperty:
case Kind::SettableProperty:
Expand All @@ -2462,10 +2440,9 @@ class KeyPathPatternComponent {
case Kind::OptionalChain:
case Kind::OptionalForce:
case Kind::OptionalWrap:
case Kind::External:
llvm_unreachable("not a settable computed property");
case Kind::SettableProperty:
return Computed.SetterAndIdKind.getPointer();
return SetterAndIdKind.getPointer();
}
llvm_unreachable("unhandled kind");
}
Expand All @@ -2479,7 +2456,6 @@ class KeyPathPatternComponent {
return {};
case Kind::GettableProperty:
case Kind::SettableProperty:
case Kind::External:
return Indices;
}
}
Expand All @@ -2491,7 +2467,6 @@ class KeyPathPatternComponent {
case Kind::OptionalForce:
case Kind::OptionalWrap:
llvm_unreachable("not a computed property");
case Kind::External:
case Kind::GettableProperty:
case Kind::SettableProperty:
return IndexEquality.Equal;
Expand All @@ -2504,7 +2479,6 @@ class KeyPathPatternComponent {
case Kind::OptionalForce:
case Kind::OptionalWrap:
llvm_unreachable("not a computed property");
case Kind::External:
case Kind::GettableProperty:
case Kind::SettableProperty:
return IndexEquality.Hash;
Expand All @@ -2519,15 +2493,29 @@ class KeyPathPatternComponent {
}

AbstractStorageDecl *getExternalDecl() const {
assert(getKind() == Kind::External
&& "not an external property");
return (AbstractStorageDecl*)ValueAndKind.getPointer();
switch (getKind()) {
case Kind::StoredProperty:
case Kind::OptionalChain:
case Kind::OptionalForce:
case Kind::OptionalWrap:
llvm_unreachable("not a computed property");
case Kind::GettableProperty:
case Kind::SettableProperty:
return ExternalStorage;
}
}

SubstitutionMap getExternalSubstitutions() const {
assert(getKind() == Kind::External
&& "not an external property");
return ExternalSubstitutions;
switch (getKind()) {
case Kind::StoredProperty:
case Kind::OptionalChain:
case Kind::OptionalForce:
case Kind::OptionalWrap:
llvm_unreachable("not a computed property");
case Kind::GettableProperty:
case Kind::SettableProperty:
return ExternalSubstitutions;
}
}

static KeyPathPatternComponent
Expand All @@ -2536,10 +2524,14 @@ class KeyPathPatternComponent {
ArrayRef<Index> indices,
SILFunction *indicesEquals,
SILFunction *indicesHash,
AbstractStorageDecl *externalDecl,
SubstitutionMap externalSubs,
CanType ty) {
return KeyPathPatternComponent(identifier,
getter, nullptr, indices,
indicesEquals, indicesHash, ty);
indicesEquals, indicesHash,
externalDecl, externalSubs,
ty);
}

static KeyPathPatternComponent
Expand All @@ -2549,10 +2541,14 @@ class KeyPathPatternComponent {
ArrayRef<Index> indices,
SILFunction *indicesEquals,
SILFunction *indicesHash,
AbstractStorageDecl *externalDecl,
SubstitutionMap externalSubs,
CanType ty) {
return KeyPathPatternComponent(identifier,
getter, setter, indices,
indicesEquals, indicesHash, ty);
indicesEquals, indicesHash,
externalDecl, externalSubs,
ty);
}

static KeyPathPatternComponent
Expand All @@ -2568,23 +2564,11 @@ class KeyPathPatternComponent {
case Kind::StoredProperty:
case Kind::GettableProperty:
case Kind::SettableProperty:
case Kind::External:
llvm_unreachable("not an optional kind");
}
return KeyPathPatternComponent(kind, ty);
}

static KeyPathPatternComponent
forExternal(AbstractStorageDecl *externalDecl,
SubstitutionMap substitutions,
ArrayRef<Index> indices,
SILFunction *indicesEquals,
SILFunction *indicesHash,
CanType ty) {
return KeyPathPatternComponent(externalDecl, substitutions,
indices, indicesEquals, indicesHash, ty);
}

void incrementRefCounts() const;
void decrementRefCounts() const;

Expand Down
2 changes: 1 addition & 1 deletion include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const uint16_t VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t VERSION_MINOR = 425; // Last change: access impls
const uint16_t VERSION_MINOR = 426; // SIL key path external components with local attempts

using DeclIDField = BCFixed<31>;

Expand Down
95 changes: 1 addition & 94 deletions lib/IRGen/GenKeyPath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -623,8 +623,7 @@ getInitializerForComputedComponent(IRGenModule &IGM,
// External components don't need to store the key path environment (and
// can't), since they need to already have enough information to function
// independently of any context using the component.
if (genericEnv &&
component.getKind() != KeyPathPatternComponent::Kind::External) {
if (genericEnv) {
auto destGenericEnv = dest;
if (!component.getSubscriptIndices().empty()) {
auto genericEnvAlignMask = llvm::ConstantInt::get(IGM.SizeTy,
Expand Down Expand Up @@ -703,28 +702,6 @@ emitMetadataGeneratorForKeyPath(IRGenModule &IGM,
});
};

static llvm::Function *
emitWitnessTableGeneratorForKeyPath(IRGenModule &IGM,
CanType type,
ProtocolConformanceRef conformance,
GenericEnvironment *genericEnv,
ArrayRef<GenericRequirement> requirements) {
// TODO: Use the standard conformance accessor when there are no arguments
// and the conformance accessor is defined.
return emitGeneratorForKeyPath(IGM, "keypath_get_witness_table", type,
IGM.WitnessTablePtrTy,
genericEnv, requirements,
[&](IRGenFunction &IGF, CanType substType) {
if (type->hasTypeParameter())
conformance = conformance.subst(type,
QueryInterfaceTypeSubstitutions(genericEnv),
LookUpConformanceInSignature(*genericEnv->getGenericSignature()));
auto ret = emitWitnessTableRef(IGF, substType, conformance);
IGF.Builder.CreateRet(ret);
});
}


static void
emitKeyPathComponent(IRGenModule &IGM,
ConstantStructBuilder &fields,
Expand All @@ -745,75 +722,6 @@ emitKeyPathComponent(IRGenModule &IGM,
loweredBaseTy = IGM.getLoweredType(AbstractionPattern::getOpaque(),
baseTy->getWithoutSpecifierType());
switch (auto kind = component.getKind()) {
case KeyPathPatternComponent::Kind::External: {
fields.addInt32(KeyPathComponentHeader::forExternalComponent().getData());
// Emit accessors for all of the external declaration's necessary
// bindings.
SmallVector<llvm::Constant*, 4> descriptorArgs;
auto componentSig = component.getExternalDecl()->getInnermostDeclContext()
->getGenericSignatureOfContext();
auto subs = component.getExternalSubstitutions();
enumerateGenericSignatureRequirements(
componentSig->getCanonicalSignature(),
[&](GenericRequirement reqt) {
auto substType = reqt.TypeParameter.subst(subs)
->getCanonicalType();
if (!reqt.Protocol) {
// Type requirement.
descriptorArgs.push_back(
emitMetadataGeneratorForKeyPath(IGM, substType,
genericEnv, requirements));
} else {
// Protocol requirement.
auto conformance = subs.lookupConformance(
reqt.TypeParameter->getCanonicalType(), reqt.Protocol);
descriptorArgs.push_back(
emitWitnessTableGeneratorForKeyPath(IGM, substType,
*conformance,
genericEnv, requirements));
}
});
// If instantiable in-place, pad out the argument count here to ensure
// there's room enough to instantiate a settable computed property
// with two captured words in-place. The runtime instantiation of the
// external component will ignore the padding, and this will make in-place
// instantiation more likely to avoid needing an allocation.
unsigned argSize = descriptorArgs.size();
if (isInstantiableInPlace) {
argSize = std::max(argSize, 3u);
}

fields.addInt32(argSize);
fields.add(IGM.getAddrOfPropertyDescriptor(component.getExternalDecl()));

// Add an initializer function that copies generic arguments out of the
// pattern argument buffer into the instantiated object, along with the
// index equality/hash operations we have from our perspective, or null
// if there are no arguments.
if (component.getSubscriptIndices().empty()) {
fields.addInt(IGM.IntPtrTy, 0);
fields.addInt(IGM.IntPtrTy, 0);
fields.addInt(IGM.IntPtrTy, 0);
} else {
fields.add(getInitializerForComputedComponent(IGM, component,
operands,
genericEnv,
requirements));
fields.add(IGM.getAddrOfSILFunction(component.getSubscriptIndexEquals(),
NotForDefinition));
fields.add(IGM.getAddrOfSILFunction(component.getSubscriptIndexHash(),
NotForDefinition));
}

// Add the generic arguments for the external context.
for (auto arg : descriptorArgs)
fields.add(arg);

// Add padding.
for (unsigned i = descriptorArgs.size(); i < argSize; ++i)
fields.addInt(IGM.IntPtrTy, 0);
break;
}
case KeyPathPatternComponent::Kind::StoredProperty: {
auto property = cast<VarDecl>(component.getStoredPropertyDecl());

Expand Down Expand Up @@ -1162,7 +1070,6 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern,
switch (component.getKind()) {
case KeyPathPatternComponent::Kind::GettableProperty:
case KeyPathPatternComponent::Kind::SettableProperty:
case KeyPathPatternComponent::Kind::External:
for (auto &index : component.getSubscriptIndices()) {
operands[index.Operand].LoweredType = index.LoweredType;
operands[index.Operand].LastUser = &component;
Expand Down
Loading