Skip to content

[pull] swiftwasm from main #4582

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 7 commits into from
May 21, 2022
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
3 changes: 3 additions & 0 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -5918,6 +5918,9 @@ class OpenedArchetypeType final : public ArchetypeType,
LayoutConstraint layout);
};
BEGIN_CAN_TYPE_WRAPPER(OpenedArchetypeType, ArchetypeType)
CanOpenedArchetypeType getRoot() const {
return CanOpenedArchetypeType(getPointer()->getRoot());
}
END_CAN_TYPE_WRAPPER(OpenedArchetypeType, ArchetypeType)

/// An archetype that represents an opaque element of a type sequence in context.
Expand Down
2 changes: 1 addition & 1 deletion include/swift/SILOptimizer/Utils/Existential.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace swift {
/// When successfull, ConcreteExistentialInfo can be used to determine the
/// concrete type of the opened existential.
struct OpenedArchetypeInfo {
ArchetypeType *OpenedArchetype = nullptr;
OpenedArchetypeType *OpenedArchetype = nullptr;
// The opened value.
SingleValueInstruction *OpenedArchetypeValue;
// The existential value.
Expand Down
7 changes: 7 additions & 0 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ Type QueryTypeSubstitutionMap::operator()(SubstitutableType *type) const {

Type
QueryTypeSubstitutionMapOrIdentity::operator()(SubstitutableType *type) const {
// FIXME: Type::subst should not be pass in non-root archetypes.
// Consider only root archetypes.
if (auto *archetype = dyn_cast<ArchetypeType>(type)) {
if (!archetype->isRoot())
return Type();
}

auto key = type->getCanonicalType()->castTo<SubstitutableType>();
auto known = substitutions.find(key);
if (known != substitutions.end() && known->second)
Expand Down
18 changes: 8 additions & 10 deletions lib/SIL/IR/SILFunctionType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2551,7 +2551,7 @@ CanSILFunctionType swift::buildSILFunctionThunkType(
auto archetypeVisitor = [&](CanType t) {
if (auto archetypeTy = dyn_cast<ArchetypeType>(t)) {
if (auto opened = dyn_cast<OpenedArchetypeType>(archetypeTy)) {
const auto root = cast<OpenedArchetypeType>(CanType(opened->getRoot()));
const auto root = opened.getRoot();
assert((openedExistential == CanArchetypeType() ||
openedExistential == root) &&
"one too many open existentials");
Expand Down Expand Up @@ -2582,18 +2582,16 @@ CanSILFunctionType swift::buildSILFunctionThunkType(
}

auto substTypeHelper = [&](SubstitutableType *type) -> Type {
// FIXME: Type::subst should not pass in non-root archetypes.
// Consider only root archetypes.
if (auto *archetype = dyn_cast<ArchetypeType>(type)) {
if (!archetype->isRoot())
return Type();
}

if (CanType(type) == openedExistential)
return newArchetype;

// If a nested archetype is rooted on our opened existential, fail:
// Type::subst attempts to substitute the parent of a nested archetype
// only if it fails to find a replacement for the nested one.
if (auto *opened = dyn_cast<OpenedArchetypeType>(type)) {
if (openedExistential->isEqual(opened->getRoot())) {
return nullptr;
}
}

return Type(type).subst(contextSubs);
};
auto substConformanceHelper =
Expand Down
2 changes: 1 addition & 1 deletion lib/SIL/IR/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ static void collectDependentTypeInfo(
return;
Ty.visit([&](CanType t) {
if (const auto opened = dyn_cast<OpenedArchetypeType>(t)) {
const auto root = cast<OpenedArchetypeType>(CanType(opened->getRoot()));
const auto root = opened.getRoot();

// Add this root opened archetype if it was not seen yet.
// We don't use a set here, because the number of open archetypes
Expand Down
12 changes: 4 additions & 8 deletions lib/SIL/Verifier/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1469,10 +1469,8 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
"Operand is of an ArchetypeType that does not exist in the "
"Caller's generic param list.");
if (auto OpenedA = getOpenedArchetypeOf(A)) {
const auto root =
cast<OpenedArchetypeType>(CanType(OpenedA->getRoot()));
auto *openingInst =
F->getModule().getRootOpenedArchetypeDefInst(root, F);
F->getModule().getRootOpenedArchetypeDefInst(OpenedA.getRoot(), F);
require(I == nullptr || openingInst == I ||
properlyDominates(openingInst, I),
"Use of an opened archetype should be dominated by a "
Expand Down Expand Up @@ -1605,7 +1603,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
require(isArchetypeValidInFunction(A, AI->getFunction()),
"Archetype to be substituted must be valid in function.");

const auto root = cast<OpenedArchetypeType>(CanType(A->getRoot()));
const auto root = A.getRoot();

// Collect all root opened archetypes used in the substitutions list.
FoundRootOpenedArchetypes.insert(root);
Expand Down Expand Up @@ -4074,10 +4072,8 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
Ty.visit([&](CanType t) {
SILValue Def;
if (const auto archetypeTy = dyn_cast<OpenedArchetypeType>(t)) {
const auto root =
cast<OpenedArchetypeType>(CanType(archetypeTy->getRoot()));
Def = I->getModule().getRootOpenedArchetypeDefInst(root,
I->getFunction());
Def = I->getModule().getRootOpenedArchetypeDefInst(
archetypeTy.getRoot(), I->getFunction());
require(Def, "Root opened archetype should be registered in SILModule");
} else if (t->hasDynamicSelfType()) {
require(I->getFunction()->hasSelfParam() ||
Expand Down
107 changes: 53 additions & 54 deletions lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -920,45 +920,56 @@ static bool canReplaceCopiedArg(FullApplySite Apply, SILValue Arg,
return true;
}

/// Determine if the result type or argument types of the given apply, except
/// for the argument at \p SkipArgIdx, contain an opened archetype rooted
/// on \p RootOA.
static bool applyInvolvesOpenedArchetypeWithRoot(FullApplySite Apply,
OpenedArchetypeType *RootOA,
unsigned SkipArgIdx) {
if (Apply.getType().getASTType()->hasOpenedExistentialWithRoot(RootOA)) {
return true;
}

const auto NumApplyArgs = Apply.getNumArguments();
for (unsigned Idx = 0; Idx < NumApplyArgs; ++Idx) {
if (Idx == SkipArgIdx)
continue;
if (Apply.getArgument(Idx)
->getType()
.getASTType()
->hasOpenedExistentialWithRoot(RootOA)) {
return true;
}
}

return false;
}

// Check the legal conditions under which a Arg parameter (specified as ArgIdx)
// can be replaced with a concrete type. Concrete type info is passed as CEI
// argument.
bool SILCombiner::canReplaceArg(FullApplySite Apply,
const OpenedArchetypeInfo &OAI,
const ConcreteExistentialInfo &CEI,
unsigned ArgIdx) {

// Don't specialize apply instructions that return the callee's Arg type,
// because this optimization does not know how to substitute types in the
// users of this apply. In the function type substitution below, all
// references to OpenedArchetype will be substituted. So walk to type to
// find all possible references, such as returning Optional<Arg>.
if (Apply.getType().getASTType().findIf(
[&OAI](Type t) -> bool { return t->isEqual(OAI.OpenedArchetype); })) {
return false;
}
// Bail out if any other arguments or indirect result that refer to the
// OpenedArchetype. The following optimization substitutes all occurrences
// of OpenedArchetype in the function signature, but will only rewrite the
// Arg operand.
// Don't specialize apply instructions if the result type references
// OpenedArchetype, because this optimization does not know how to substitute
// types in the users of this apply. In the function type substitution below,
// all references to OpenedArchetype will be substituted. So walk the type to
// find all possible references, such as returning Optional<OpenedArchetype>.
// The same holds for other arguments or indirect result that refer to the
// OpenedArchetype, because the following optimization will rewrite only the
// argument at ArgIdx.
//
// Note that the language does not allow Self to occur in contravariant
// position. However, SIL does allow this and it can happen as a result of
// upstream transformations. Since this is bail-out logic, it must handle
// all verifiable SIL.

// This bailout check is also needed for non-Self arguments [including Self].
unsigned NumApplyArgs = Apply.getNumArguments();
for (unsigned Idx = 0; Idx < NumApplyArgs; ++Idx) {
if (Idx == ArgIdx)
continue;
if (Apply.getArgument(Idx)->getType().getASTType().findIf(
[&OAI](Type t) -> bool {
return t->isEqual(OAI.OpenedArchetype);
})) {
return false;
}
if (applyInvolvesOpenedArchetypeWithRoot(Apply, OAI.OpenedArchetype,
ArgIdx)) {
return false;
}

// If the convention is mutating, then the existential must have been
// initialized by copying the concrete value (regardless of whether
// CEI.isConcreteValueCopied is true). Replacing the existential address with
Expand Down Expand Up @@ -1052,37 +1063,24 @@ SILValue SILCombiner::canCastArg(FullApplySite Apply,
!CEI.ConcreteValue->getType().isAddress())
return SILValue();

// Don't specialize apply instructions that return the callee's Arg type,
// because this optimization does not know how to substitute types in the
// users of this apply. In the function type substitution below, all
// references to OpenedArchetype will be substituted. So walk to type to
// find all possible references, such as returning Optional<Arg>.
if (Apply.getType().getASTType().findIf(
[&OAI](Type t) -> bool { return t->isEqual(OAI.OpenedArchetype); })) {
return SILValue();
}
// Bail out if any other arguments or indirect result that refer to the
// OpenedArchetype. The following optimization substitutes all occurrences
// of OpenedArchetype in the function signature, but will only rewrite the
// Arg operand.
// Don't specialize apply instructions if the result type references
// OpenedArchetype, because this optimization does not know how to substitute
// types in the users of this apply. In the function type substitution below,
// all references to OpenedArchetype will be substituted. So walk the type to
// find all possible references, such as returning Optional<OpenedArchetype>.
// The same holds for other arguments or indirect result that refer to the
// OpenedArchetype, because the following optimization will rewrite only the
// argument at ArgIdx.
//
// Note that the language does not allow Self to occur in contravariant
// position. However, SIL does allow this and it can happen as a result of
// upstream transformations. Since this is bail-out logic, it must handle
// all verifiable SIL.

// This bailout check is also needed for non-Self arguments [including Self].
unsigned NumApplyArgs = Apply.getNumArguments();
for (unsigned Idx = 0; Idx < NumApplyArgs; ++Idx) {
if (Idx == ArgIdx)
continue;
if (Apply.getArgument(Idx)->getType().getASTType().findIf(
[&OAI](Type t) -> bool {
return t->isEqual(OAI.OpenedArchetype);
})) {
return SILValue();
}
if (applyInvolvesOpenedArchetypeWithRoot(Apply, OAI.OpenedArchetype,
ArgIdx)) {
return SILValue();
}

return Builder.createUncheckedAddrCast(
Apply.getLoc(), Apply.getArgument(ArgIdx), CEI.ConcreteValue->getType());
}
Expand Down Expand Up @@ -1293,10 +1291,11 @@ SILInstruction *SILCombiner::createApplyWithConcreteType(
/// %existential = alloc_stack $Protocol
/// %value = init_existential_addr %existential : $Concrete
/// copy_addr ... to %value
/// %witness = witness_method $@opened
/// apply %witness<T : Protocol>(%existential)
/// %opened = open_existential_addr %existential
/// %witness = witness_method $@opened(...) Protocol
/// apply %witness<$@opened(...) Protocol>(%opened)
///
/// ==> apply %witness<Concrete : Protocol>(%existential)
/// ==> apply %witness<$Concrete>(%existential)
SILInstruction *
SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
WitnessMethodInst *WMI) {
Expand Down
49 changes: 25 additions & 24 deletions lib/SILOptimizer/Utils/Devirtualize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1094,9 +1094,10 @@ static bool canDevirtualizeWitnessMethod(ApplySite applySite) {
return false;
}

// FIXME: devirtualizeWitnessMethod below does not support cases with
// covariant 'Self' nested inside a collection type,
// like '[Self]' or '[* : Self]'.
// FIXME: devirtualizeWitnessMethod does not support cases with covariant
// 'Self'-rooted type parameters nested inside a collection type, like
// '[Self]' or '[* : Self.A]', because it doesn't know how to deal with
// associated collection upcasts.
const Type interfaceTy = wmi->getMember()
.getDecl()
->getInterfaceType()
Expand All @@ -1107,35 +1108,35 @@ static bool canDevirtualizeWitnessMethod(ApplySite applySite) {
if (!interfaceTy->hasTypeParameter())
return true;

class HasSelfNestedInsideCollection final : public TypeWalker {
unsigned CollectionDepth;
auto *const selfGP = wmi->getLookupProtocol()->getProtocolSelfType();
auto isSelfRootedTypeParameter = [selfGP](Type T) -> bool {
if (!T->hasTypeParameter())
return false;

public:
Action walkToTypePre(Type T) override {
if (!T->hasTypeParameter())
return Action::SkipChildren;
if (T->isTypeParameter()) {
return T->getRootGenericParam()->isEqual(selfGP);
}

if (auto *GP = T->getAs<GenericTypeParamType>()) {
// Only 'Self' will have zero depth in the type of a requirement.
if (GP->getDepth() == 0 && CollectionDepth)
return Action::Stop;
}
return false;
};

if (T->isArray() || T->isDictionary())
++CollectionDepth;
return !interfaceTy.findIf([&](Type T) -> bool {
if (!T->hasTypeParameter())
return false;

return Action::Continue;
if (T->isArray() || T->isDictionary()) {
return T.findIf(isSelfRootedTypeParameter);
}

Action walkToTypePost(Type T) override {
if (T->isArray() || T->isDictionary())
--CollectionDepth;

return Action::Continue;
if (auto *FT = T->getAs<FunctionType>()) {
for (const auto &Param : FT->getParams()) {
if (Param.isVariadic() && T.findIf(isSelfRootedTypeParameter))
return true;
}
}
};

return !interfaceTy.walk(HasSelfNestedInsideCollection());
return false;
});
}

/// In the cases where we can statically determine the function that
Expand Down
6 changes: 3 additions & 3 deletions lib/SILOptimizer/Utils/Existential.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,13 +220,13 @@ OpenedArchetypeInfo::OpenedArchetypeInfo(Operand &use) {
}
}
if (auto *Open = dyn_cast<OpenExistentialAddrInst>(openedVal)) {
OpenedArchetype = Open->getType().castTo<ArchetypeType>();
OpenedArchetype = Open->getType().castTo<OpenedArchetypeType>();
OpenedArchetypeValue = Open;
ExistentialValue = Open->getOperand();
return;
}
if (auto *Open = dyn_cast<OpenExistentialRefInst>(openedVal)) {
OpenedArchetype = Open->getType().castTo<ArchetypeType>();
OpenedArchetype = Open->getType().castTo<OpenedArchetypeType>();
OpenedArchetypeValue = Open;
ExistentialValue = Open->getOperand();
return;
Expand All @@ -235,7 +235,7 @@ OpenedArchetypeInfo::OpenedArchetypeInfo(Operand &use) {
auto Ty = Open->getType().getASTType();
while (auto Metatype = dyn_cast<MetatypeType>(Ty))
Ty = Metatype.getInstanceType();
OpenedArchetype = cast<ArchetypeType>(Ty);
OpenedArchetype = cast<OpenedArchetypeType>(Ty);
OpenedArchetypeValue = Open;
ExistentialValue = Open->getOperand();
}
Expand Down
Loading