@@ -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 , const ConcreteExistentialInfo *> CEIs;
698+ CEIs.insert (std::pair<unsigned , const 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,54 @@ 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 && (!CEI.InitExistential ||
799+ !canReplaceCopiedArg (Apply, CEI.InitExistential , DA, ArgIdx))) {
800+ return false ;
801+ }
802+ // It is safe to replace Arg.
803+ return true ;
804+ }
805+
754806// / Rewrite the given method apply instruction in terms of the provided conrete
755807// / type information.
756808// /
@@ -774,74 +826,61 @@ static bool canReplaceCopiedSelf(FullApplySite Apply,
774826// / FIXME: Protocol methods (witness or default) that return Self will be given
775827// / a new return type. This implementation fails to update the type signature of
776828// / 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 ());
829+ SILInstruction *SILCombiner::createApplyWithConcreteType (
830+ FullApplySite Apply,
831+ const llvm::SmallDenseMap<unsigned , const ConcreteExistentialInfo *> &CEIs,
832+ SILBuilderContext &BuilderCtx) {
782833
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- }
834+ // Ensure that the callee is polymorphic.
835+ assert (Apply.getOrigCalleeType ()->isPolymorphic ());
814836
815- // Create a set of arguments.
837+ // Create the new set of arguments to apply including their substitutions.
838+ SubstitutionMap NewCallSubs = Apply.getSubstitutionMap ();
816839 SmallVector<SILValue, 8 > NewArgs;
817- for (auto Arg : Apply.getArgumentsWithoutSelf ()) {
818- NewArgs.push_back (Arg);
840+ unsigned NumApplyArgs = Apply.getNumArguments ();
841+ bool UpdatedArgs = false ;
842+ for (unsigned ArgIdx = 0 ; ArgIdx < NumApplyArgs; ArgIdx++) {
843+ auto ArgIt = CEIs.find (ArgIdx);
844+ if (ArgIt == CEIs.end ()) {
845+ // Use the old argument if it does not have a valid concrete existential.
846+ NewArgs.push_back (Apply.getArgument (ArgIdx));
847+ continue ;
848+ }
849+ auto *CEI = ArgIt->second ;
850+ // Check for Arg's concrete type propagation legality.
851+ if (!canReplaceArg (Apply, *CEI, ArgIdx)) {
852+ NewArgs.push_back (Apply.getArgument (ArgIdx));
853+ continue ;
854+ }
855+ UpdatedArgs = true ;
856+ // Ensure that we have a concrete value to propagate.
857+ assert (CEI->ConcreteValue );
858+ NewArgs.push_back (CEI->ConcreteValue );
859+ // Form a new set of substitutions where the argument is
860+ // replaced with a concrete type.
861+ NewCallSubs = NewCallSubs.subst (
862+ [&](SubstitutableType *type) -> Type {
863+ if (type == CEI->OpenedArchetype )
864+ return CEI->ConcreteType ;
865+ return type;
866+ },
867+ [&](CanType origTy, Type substTy,
868+ ProtocolDecl *proto) -> Optional<ProtocolConformanceRef> {
869+ if (origTy->isEqual (CEI->OpenedArchetype )) {
870+ assert (substTy->isEqual (CEI->ConcreteType ));
871+ // Do a conformance lookup on this witness requirement using the
872+ // existential's conformances. The witness requirement may be a
873+ // base type of the existential's requirements.
874+ return CEI->lookupExistentialConformance (proto);
875+ }
876+ return ProtocolConformanceRef (proto);
877+ });
819878 }
820- NewArgs.push_back (CEI.ConcreteValue );
821-
822- assert (Apply.getOrigCalleeType ()->isPolymorphic ());
823879
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- });
880+ if (!UpdatedArgs)
881+ return nullptr ;
844882
883+ // Now create the new apply instruction.
845884 SILBuilderWithScope ApplyBuilder (Apply.getInstruction (), BuilderCtx);
846885 FullApplySite NewApply;
847886 if (auto *TAI = dyn_cast<TryApplyInst>(Apply))
@@ -920,8 +959,12 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
920959 replaceWitnessMethodInst (WMI, BuilderCtx, CEI.ConcreteType ,
921960 SelfConformance);
922961 }
962+ // Construct the map for Self to be used for createApplyWithConcreteType.
963+ llvm::SmallDenseMap<unsigned , const ConcreteExistentialInfo *> CEIs;
964+ CEIs.insert (std::pair<unsigned , const ConcreteExistentialInfo *>(
965+ Apply.getCalleeArgIndex (Apply.getSelfArgumentOperand ()), &CEI));
923966 // Try to rewrite the apply.
924- return createApplyWithConcreteType (Apply, CEI , BuilderCtx);
967+ return createApplyWithConcreteType (Apply, CEIs , BuilderCtx);
925968}
926969
927970// / Rewrite a protocol extension lookup type from an archetype to a concrete
@@ -936,27 +979,36 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
936979// / ==> apply %f<C : P>(%ref)
937980SILInstruction *
938981SILCombiner::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 ())
982+ // This optimization requires a generic argument.
983+ if (!Apply.hasSubstitutions ())
947984 return nullptr ;
948985
949986 SILBuilderContext BuilderCtx (Builder.getModule (), Builder.getTrackingList ());
950987 SILOpenedArchetypesTracker OpenedArchetypesTracker (&Builder.getFunction ());
951988 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 );
989+ llvm::SmallDenseMap<unsigned , const ConcreteExistentialInfo *> CEIs;
990+ for (unsigned ArgIdx = 0 ; ArgIdx < Apply.getNumArguments (); ArgIdx++) {
991+ auto ArgASTType = Apply.getArgument (ArgIdx)->getType ().getASTType ();
992+ if (!ArgASTType->hasArchetype ())
993+ continue ;
994+ const ConcreteExistentialInfo CEI (Apply.getArgumentOperands ()[ArgIdx]);
995+ if (!CEI.isValid ())
996+ continue ;
997+
998+ CEIs.insert (
999+ std::pair<unsigned , const 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