@@ -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 , ConcreteExistentialInfo> CEIs;
698
+ CEIs.insert (std::pair<unsigned , 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,55 @@ 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 &&
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
+
754
807
// / Rewrite the given method apply instruction in terms of the provided conrete
755
808
// / type information.
756
809
// /
@@ -774,74 +827,61 @@ static bool canReplaceCopiedSelf(FullApplySite Apply,
774
827
// / FIXME: Protocol methods (witness or default) that return Self will be given
775
828
// / a new return type. This implementation fails to update the type signature of
776
829
// / 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) {
782
834
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 ());
814
837
815
- // Create a set of arguments.
838
+ // Create the new set of arguments to apply including their substitutions.
839
+ SubstitutionMap NewCallSubs = Apply.getSubstitutionMap ();
816
840
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
+ });
819
879
}
820
- NewArgs.push_back (CEI.ConcreteValue );
821
-
822
- assert (Apply.getOrigCalleeType ()->isPolymorphic ());
823
880
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 ;
844
883
884
+ // Now create the new apply instruction.
845
885
SILBuilderWithScope ApplyBuilder (Apply.getInstruction (), BuilderCtx);
846
886
FullApplySite NewApply;
847
887
if (auto *TAI = dyn_cast<TryApplyInst>(Apply))
@@ -920,8 +960,12 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
920
960
replaceWitnessMethodInst (WMI, BuilderCtx, CEI.ConcreteType ,
921
961
SelfConformance);
922
962
}
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));
923
967
// Try to rewrite the apply.
924
- return createApplyWithConcreteType (Apply, CEI , BuilderCtx);
968
+ return createApplyWithConcreteType (Apply, CEIs , BuilderCtx);
925
969
}
926
970
927
971
// / Rewrite a protocol extension lookup type from an archetype to a concrete
@@ -936,27 +980,35 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
936
980
// / ==> apply %f<C : P>(%ref)
937
981
SILInstruction *
938
982
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 ())
983
+ // This optimization requires a generic argument.
984
+ if (!Apply.hasSubstitutions ())
947
985
return nullptr ;
948
986
949
987
SILBuilderContext BuilderCtx (Builder.getModule (), Builder.getTrackingList ());
950
988
SILOpenedArchetypesTracker OpenedArchetypesTracker (&Builder.getFunction ());
951
989
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
+ }
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