@@ -693,22 +693,26 @@ SILCombiner::propagateSoleConformingType(FullApplySite Apply,
693
693
SILBuilderContext BuilderCtx (M, Builder.getTrackingList ());
694
694
replaceWitnessMethodInst (WMI, BuilderCtx, ConcreteType,
695
695
*(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));
696
700
// / Create the new apply instruction using the concrete type.
697
- auto *NewAI = createApplyWithConcreteType (Apply, CEI , BuilderCtx);
701
+ auto *NewAI = createApplyWithConcreteType (Apply, CEIs , BuilderCtx);
698
702
return NewAI;
699
703
}
700
704
701
705
// / Given an Apply and an argument value produced by InitExistentialAddrInst,
702
706
// / return true if the argument can be replaced by a copy of its value.
703
707
// /
704
708
// / FIXME: remove this helper when we can assume SIL opaque values.
705
- static bool canReplaceCopiedSelf (FullApplySite Apply,
709
+ static bool canReplaceCopiedArg (FullApplySite Apply,
706
710
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
709
713
// 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 ())
712
716
return false ;
713
717
714
718
auto *DT = DA->get (Apply.getFunction ());
@@ -751,6 +755,54 @@ static bool canReplaceCopiedSelf(FullApplySite Apply,
751
755
return true ;
752
756
}
753
757
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
+
754
806
// / Rewrite the given method apply instruction in terms of the provided conrete
755
807
// / type information.
756
808
// /
@@ -774,74 +826,61 @@ static bool canReplaceCopiedSelf(FullApplySite Apply,
774
826
// / FIXME: Protocol methods (witness or default) that return Self will be given
775
827
// / a new return type. This implementation fails to update the type signature of
776
828
// / 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) {
782
833
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 ());
814
836
815
- // Create a set of arguments.
837
+ // Create the new set of arguments to apply including their substitutions.
838
+ SubstitutionMap NewCallSubs = Apply.getSubstitutionMap ();
816
839
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
+ });
819
878
}
820
- NewArgs.push_back (CEI.ConcreteValue );
821
-
822
- assert (Apply.getOrigCalleeType ()->isPolymorphic ());
823
879
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 ;
844
882
883
+ // Now create the new apply instruction.
845
884
SILBuilderWithScope ApplyBuilder (Apply.getInstruction (), BuilderCtx);
846
885
FullApplySite NewApply;
847
886
if (auto *TAI = dyn_cast<TryApplyInst>(Apply))
@@ -920,8 +959,12 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
920
959
replaceWitnessMethodInst (WMI, BuilderCtx, CEI.ConcreteType ,
921
960
SelfConformance);
922
961
}
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));
923
966
// Try to rewrite the apply.
924
- return createApplyWithConcreteType (Apply, CEI , BuilderCtx);
967
+ return createApplyWithConcreteType (Apply, CEIs , BuilderCtx);
925
968
}
926
969
927
970
// / Rewrite a protocol extension lookup type from an archetype to a concrete
@@ -936,27 +979,36 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
936
979
// / ==> apply %f<C : P>(%ref)
937
980
SILInstruction *
938
981
SILCombiner::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 ())
947
984
return nullptr ;
948
985
949
986
SILBuilderContext BuilderCtx (Builder.getModule (), Builder.getTrackingList ());
950
987
SILOpenedArchetypesTracker OpenedArchetypesTracker (&Builder.getFunction ());
951
988
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
+ }
957
1007
}
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);
960
1012
}
961
1013
962
1014
// / \brief Check that all users of the apply are retain/release ignoring one
0 commit comments