@@ -693,22 +693,26 @@ SILCombiner::propagateSoleConformingType(FullApplySite Apply,
693693 SILBuilderContext BuilderCtx (M, Builder.getTrackingList ());
694694 replaceWitnessMethodInst (WMI, BuilderCtx, ConcreteType,
695695 *(CEI.ExistentialSubs .getConformances ().begin ()));
696+ // Construct the map for Self to be used for createApplyWithConcreteType.
697+ llvm::SmallDenseMap<unsigned , ConcreteExistentialInfo> CEIs;
698+ CEIs.insert (std::pair<unsigned , ConcreteExistentialInfo>(
699+ Apply.getCalleeArgIndex (Apply.getSelfArgumentOperand ()), CEI));
696700 // / Create the new apply instruction using the concrete type.
697- auto *NewAI = createApplyWithConcreteType (Apply, CEI , BuilderCtx);
701+ auto *NewAI = createApplyWithConcreteType (Apply, CEIs , BuilderCtx);
698702 return NewAI;
699703}
700704
701705// / Given an Apply and an argument value produced by InitExistentialAddrInst,
702706// / return true if the argument can be replaced by a copy of its value.
703707// /
704708// / FIXME: remove this helper when we can assume SIL opaque values.
705- static bool canReplaceCopiedSelf (FullApplySite Apply,
709+ static bool canReplaceCopiedArg (FullApplySite Apply,
706710 SILInstruction *InitExistential,
707- DominanceAnalysis *DA) {
708- // If the witness method mutates self , we cannot replace self with
711+ DominanceAnalysis *DA, unsigned ArgIdx ) {
712+ // If the witness method mutates Arg , we cannot replace Arg with
709713 // the source of a copy. Otherwise the call would modify another value than
710- // the original self .
711- if (Apply.getOrigCalleeType ()->getSelfParameter () .isIndirectMutating ())
714+ // the original argument .
715+ if (Apply.getOrigCalleeType ()->getParameters ()[ArgIdx] .isIndirectMutating ())
712716 return false ;
713717
714718 auto *DT = DA->get (Apply.getFunction ());
@@ -751,6 +755,55 @@ static bool canReplaceCopiedSelf(FullApplySite Apply,
751755 return true ;
752756}
753757
758+ // Check the legal conditions under which a Arg parameter (specified as ArgIdx)
759+ // can be replaced with a concrete type. Concrete type info is passed as CEI
760+ // argument.
761+ bool SILCombiner::canReplaceArg (FullApplySite Apply,
762+ const ConcreteExistentialInfo &CEI,
763+ unsigned ArgIdx) {
764+
765+ // Don't specialize apply instructions that return the callee's Arg type,
766+ // because this optimization does not know how to substitute types in the
767+ // users of this apply. In the function type substitution below, all
768+ // references to OpenedArchetype will be substituted. So walk to type to
769+ // find all possible references, such as returning Optional<Arg>.
770+ if (Apply.getType ().getASTType ().findIf (
771+ [&CEI](Type t) -> bool { return t->isEqual (CEI.OpenedArchetype ); })) {
772+ return false ;
773+ }
774+ // Bail out if any other arguments or indirect result that refer to the
775+ // OpenedArchetype. The following optimization substitutes all occurrences
776+ // of OpenedArchetype in the function signature, but will only rewrite the
777+ // Arg operand.
778+ //
779+ // Note that the language does not allow Self to occur in contravariant
780+ // position. However, SIL does allow this and it can happen as a result of
781+ // upstream transformations. Since this is bail-out logic, it must handle
782+ // all verifiable SIL.
783+
784+ // This bailout check is also needed for non-Self arguments [including Self].
785+ unsigned NumApplyArgs = Apply.getNumArguments ();
786+ for (unsigned Idx = 0 ; Idx < NumApplyArgs; Idx++) {
787+ if (Idx == ArgIdx)
788+ continue ;
789+ if (Apply.getArgument (Idx)->getType ().getASTType ().findIf (
790+ [&CEI](Type t) -> bool {
791+ return t->isEqual (CEI.OpenedArchetype );
792+ })) {
793+ return false ;
794+ }
795+ }
796+ // The apply can only be rewritten in terms of the concrete value if it is
797+ // legal to pass that value as the Arg argument.
798+ if (CEI.isCopied &&
799+ (!CEI.InitExistential ||
800+ !canReplaceCopiedArg (Apply, CEI.InitExistential , DA, ArgIdx))) {
801+ return false ;
802+ }
803+ // It is safe to replace Arg.
804+ return true ;
805+ }
806+
754807// / Rewrite the given method apply instruction in terms of the provided conrete
755808// / type information.
756809// /
@@ -774,74 +827,61 @@ static bool canReplaceCopiedSelf(FullApplySite Apply,
774827// / FIXME: Protocol methods (witness or default) that return Self will be given
775828// / a new return type. This implementation fails to update the type signature of
776829// / SSA uses in those cases. Currently we bail out on methods that return Self.
777- SILInstruction *
778- SILCombiner::createApplyWithConcreteType (FullApplySite Apply,
779- const ConcreteExistentialInfo &CEI,
780- SILBuilderContext &BuilderCtx) {
781- assert (Apply.getOrigCalleeType ()->isPolymorphic ());
830+ SILInstruction *SILCombiner::createApplyWithConcreteType (
831+ FullApplySite Apply,
832+ const llvm::SmallDenseMap<unsigned , ConcreteExistentialInfo> &CEIs,
833+ SILBuilderContext &BuilderCtx) {
782834
783- // Don't specialize apply instructions that return the callee's Self type,
784- // because this optimization does not know how to substitute types in the
785- // users of this apply. In the function type substitution below, all
786- // references to OpenedArchetype will be substituted. So walk to type to find
787- // all possible references, such as returning Optional<Self>.
788- if (Apply.getType ().getASTType ().findIf (
789- [&CEI](Type t) -> bool { return t->isEqual (CEI.OpenedArchetype ); })) {
790- return nullptr ;
791- }
792- // Bail out if any non-self arguments or indirect result that refer to the
793- // OpenedArchetype. The following optimization substitutes all occurrences of
794- // OpenedArchetype in the function signature, but will only rewrite the self
795- // operand.
796- //
797- // Note that the language does not allow Self to occur in contravariant
798- // position. However, SIL does allow this and it can happen as a result of
799- // upstream transformations. Since this is bail-out logic, it must handle all
800- // verifiable SIL.
801- for (auto Arg : Apply.getArgumentsWithoutSelf ()) {
802- if (Arg->getType ().getASTType ().findIf ([&CEI](Type t) -> bool {
803- return t->isEqual (CEI.OpenedArchetype );
804- })) {
805- return nullptr ;
806- }
807- }
808- // The apply can only be rewritten in terms of the concrete value if it is
809- // legal to pass that value as the self argument.
810- if (CEI.isCopied && (!CEI.InitExistential ||
811- !canReplaceCopiedSelf (Apply, CEI.InitExistential , DA))) {
812- return nullptr ;
813- }
835+ // Ensure that the callee is polymorphic.
836+ assert (Apply.getOrigCalleeType ()->isPolymorphic ());
814837
815- // Create a set of arguments.
838+ // Create the new set of arguments to apply including their substitutions.
839+ SubstitutionMap NewCallSubs = Apply.getSubstitutionMap ();
816840 SmallVector<SILValue, 8 > NewArgs;
817- for (auto Arg : Apply.getArgumentsWithoutSelf ()) {
818- NewArgs.push_back (Arg);
841+ unsigned NumApplyArgs = Apply.getNumArguments ();
842+ bool UpdatedArgs = false ;
843+ for (unsigned ArgIdx = 0 ; ArgIdx < NumApplyArgs; ArgIdx++) {
844+ auto ArgIt = CEIs.find (ArgIdx);
845+ if (ArgIt == CEIs.end ()) {
846+ // Use the old argument if it does not have a valid concrete existential.
847+ NewArgs.push_back (Apply.getArgument (ArgIdx));
848+ continue ;
849+ }
850+ auto &CEI = ArgIt->second ;
851+ // Check for Arg's concrete type propagation legality.
852+ if (!canReplaceArg (Apply, CEI, ArgIdx)) {
853+ NewArgs.push_back (Apply.getArgument (ArgIdx));
854+ continue ;
855+ }
856+ UpdatedArgs = true ;
857+ // Ensure that we have a concrete value to propagate.
858+ assert (CEI.ConcreteValue );
859+ NewArgs.push_back (CEI.ConcreteValue );
860+ // Form a new set of substitutions where the argument is
861+ // replaced with a concrete type.
862+ NewCallSubs = NewCallSubs.subst (
863+ [&](SubstitutableType *type) -> Type {
864+ if (type == CEI.OpenedArchetype )
865+ return CEI.ConcreteType ;
866+ return type;
867+ },
868+ [&](CanType origTy, Type substTy,
869+ ProtocolDecl *proto) -> Optional<ProtocolConformanceRef> {
870+ if (origTy->isEqual (CEI.OpenedArchetype )) {
871+ assert (substTy->isEqual (CEI.ConcreteType ));
872+ // Do a conformance lookup on this witness requirement using the
873+ // existential's conformances. The witness requirement may be a
874+ // base type of the existential's requirements.
875+ return CEI.lookupExistentialConformance (proto);
876+ }
877+ return ProtocolConformanceRef (proto);
878+ });
819879 }
820- NewArgs.push_back (CEI.ConcreteValue );
821-
822- assert (Apply.getOrigCalleeType ()->isPolymorphic ());
823880
824- // Form a new set of substitutions where Self is
825- // replaced by a concrete type.
826- SubstitutionMap OrigCallSubs = Apply.getSubstitutionMap ();
827- SubstitutionMap NewCallSubs = OrigCallSubs.subst (
828- [&](SubstitutableType *type) -> Type {
829- if (type == CEI.OpenedArchetype )
830- return CEI.ConcreteType ;
831- return type;
832- },
833- [&](CanType origTy, Type substTy,
834- ProtocolDecl *proto) -> Optional<ProtocolConformanceRef> {
835- if (origTy->isEqual (CEI.OpenedArchetype )) {
836- assert (substTy->isEqual (CEI.ConcreteType ));
837- // Do a conformance lookup on this witness requirement using the
838- // existential's conformances. The witness requirement may be a base
839- // type of the existential's requirements.
840- return CEI.lookupExistentialConformance (proto).getValue ();
841- }
842- return ProtocolConformanceRef (proto);
843- });
881+ if (!UpdatedArgs)
882+ return nullptr ;
844883
884+ // Now create the new apply instruction.
845885 SILBuilderWithScope ApplyBuilder (Apply.getInstruction (), BuilderCtx);
846886 FullApplySite NewApply;
847887 if (auto *TAI = dyn_cast<TryApplyInst>(Apply))
@@ -920,8 +960,12 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
920960 replaceWitnessMethodInst (WMI, BuilderCtx, CEI.ConcreteType ,
921961 SelfConformance);
922962 }
963+ // Construct the map for Self to be used for createApplyWithConcreteType.
964+ llvm::SmallDenseMap<unsigned , ConcreteExistentialInfo> CEIs;
965+ CEIs.insert (std::pair<unsigned , ConcreteExistentialInfo>(
966+ Apply.getCalleeArgIndex (Apply.getSelfArgumentOperand ()), CEI));
923967 // Try to rewrite the apply.
924- return createApplyWithConcreteType (Apply, CEI , BuilderCtx);
968+ return createApplyWithConcreteType (Apply, CEIs , BuilderCtx);
925969}
926970
927971// / Rewrite a protocol extension lookup type from an archetype to a concrete
@@ -936,27 +980,35 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
936980// / ==> apply %f<C : P>(%ref)
937981SILInstruction *
938982SILCombiner::propagateConcreteTypeOfInitExistential (FullApplySite Apply) {
939- // This optimization requires a generic self argument.
940- if (!Apply.hasSelfArgument () || !Apply.hasSubstitutions ())
941- return nullptr ;
942-
943- // Try to derive the concrete type of self and a related conformance from
944- // the found init_existential.
945- const ConcreteExistentialInfo CEI (Apply.getSelfArgumentOperand ());
946- if (!CEI.isValid ())
983+ // This optimization requires a generic argument.
984+ if (!Apply.hasSubstitutions ())
947985 return nullptr ;
948986
949987 SILBuilderContext BuilderCtx (Builder.getModule (), Builder.getTrackingList ());
950988 SILOpenedArchetypesTracker OpenedArchetypesTracker (&Builder.getFunction ());
951989 BuilderCtx.setOpenedArchetypesTracker (&OpenedArchetypesTracker);
952- if (CEI.ConcreteType ->isOpenedExistential ()) {
953- // Temporarily record this opened existential def in this local
954- // BuilderContext before rewriting the witness method.
955- OpenedArchetypesTracker.addOpenedArchetypeDef (
956- cast<ArchetypeType>(CEI.ConcreteType ), CEI.ConcreteTypeDef );
990+ llvm::SmallDenseMap<unsigned , ConcreteExistentialInfo> CEIs;
991+ for (unsigned ArgIdx = 0 ; ArgIdx < Apply.getNumArguments (); ArgIdx++) {
992+ auto ArgASTType = Apply.getArgument (ArgIdx)->getType ().getASTType ();
993+ if (!ArgASTType->hasArchetype ())
994+ continue ;
995+ const ConcreteExistentialInfo CEI (Apply.getArgumentOperands ()[ArgIdx]);
996+ if (!CEI.isValid ())
997+ continue ;
998+
999+ CEIs.insert (std::pair<unsigned , ConcreteExistentialInfo>(ArgIdx, CEI));
1000+
1001+ if (CEI.ConcreteType ->isOpenedExistential ()) {
1002+ // Temporarily record this opened existential def in this local
1003+ // BuilderContext before rewriting the witness method.
1004+ OpenedArchetypesTracker.addOpenedArchetypeDef (
1005+ cast<ArchetypeType>(CEI.ConcreteType ), CEI.ConcreteTypeDef );
1006+ }
9571007 }
958- // Perform the transformation by rewriting the apply.
959- return createApplyWithConcreteType (Apply, CEI, BuilderCtx);
1008+ // Bail, if no argument has a concrete existential to propagate.
1009+ if (CEIs.empty ())
1010+ return nullptr ;
1011+ return createApplyWithConcreteType (Apply, CEIs, BuilderCtx);
9601012}
9611013
9621014// / \brief Check that all users of the apply are retain/release ignoring one
0 commit comments