@@ -693,26 +693,22 @@ 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));
700
696
// / Create the new apply instruction using the concrete type.
701
- auto *NewAI = createApplyWithConcreteType (Apply, CEIs , BuilderCtx);
697
+ auto *NewAI = createApplyWithConcreteType (Apply, CEI , BuilderCtx);
702
698
return NewAI;
703
699
}
704
700
705
701
// / Given an Apply and an argument value produced by InitExistentialAddrInst,
706
702
// / return true if the argument can be replaced by a copy of its value.
707
703
// /
708
704
// / FIXME: remove this helper when we can assume SIL opaque values.
709
- static bool canReplaceCopiedArg (FullApplySite Apply,
705
+ static bool canReplaceCopiedSelf (FullApplySite Apply,
710
706
SILInstruction *InitExistential,
711
- DominanceAnalysis *DA, unsigned ArgIdx ) {
712
- // If the witness method mutates Arg , we cannot replace Arg with
707
+ DominanceAnalysis *DA) {
708
+ // If the witness method mutates self , we cannot replace self with
713
709
// the source of a copy. Otherwise the call would modify another value than
714
- // the original argument .
715
- if (Apply.getOrigCalleeType ()->getParameters ()[ArgIdx] .isIndirectMutating ())
710
+ // the original self .
711
+ if (Apply.getOrigCalleeType ()->getSelfParameter () .isIndirectMutating ())
716
712
return false ;
717
713
718
714
auto *DT = DA->get (Apply.getFunction ());
@@ -755,54 +751,6 @@ static bool canReplaceCopiedArg(FullApplySite Apply,
755
751
return true ;
756
752
}
757
753
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
-
806
754
// / Rewrite the given method apply instruction in terms of the provided conrete
807
755
// / type information.
808
756
// /
@@ -826,61 +774,74 @@ bool SILCombiner::canReplaceArg(FullApplySite Apply,
826
774
// / FIXME: Protocol methods (witness or default) that return Self will be given
827
775
// / a new return type. This implementation fails to update the type signature of
828
776
// / SSA uses in those cases. Currently we bail out on methods that return Self.
829
- SILInstruction *SILCombiner::createApplyWithConcreteType (
830
- FullApplySite Apply,
831
- const llvm::SmallDenseMap<unsigned , const ConcreteExistentialInfo *> &CEIs,
832
- SILBuilderContext &BuilderCtx) {
833
-
834
- // Ensure that the callee is polymorphic.
777
+ SILInstruction *
778
+ SILCombiner::createApplyWithConcreteType (FullApplySite Apply,
779
+ const ConcreteExistentialInfo &CEI,
780
+ SILBuilderContext &BuilderCtx) {
835
781
assert (Apply.getOrigCalleeType ()->isPolymorphic ());
836
782
837
- // Create the new set of arguments to apply including their substitutions.
838
- SubstitutionMap NewCallSubs = Apply.getSubstitutionMap ();
839
- SmallVector<SILValue, 8 > NewArgs;
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 ;
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 ;
854
806
}
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
- });
878
807
}
879
-
880
- if (!UpdatedArgs)
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))) {
881
812
return nullptr ;
813
+ }
814
+
815
+ // Create a set of arguments.
816
+ SmallVector<SILValue, 8 > NewArgs;
817
+ for (auto Arg : Apply.getArgumentsWithoutSelf ()) {
818
+ NewArgs.push_back (Arg);
819
+ }
820
+ NewArgs.push_back (CEI.ConcreteValue );
821
+
822
+ assert (Apply.getOrigCalleeType ()->isPolymorphic ());
823
+
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
+ });
882
844
883
- // Now create the new apply instruction.
884
845
SILBuilderWithScope ApplyBuilder (Apply.getInstruction (), BuilderCtx);
885
846
FullApplySite NewApply;
886
847
if (auto *TAI = dyn_cast<TryApplyInst>(Apply))
@@ -959,12 +920,8 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
959
920
replaceWitnessMethodInst (WMI, BuilderCtx, CEI.ConcreteType ,
960
921
SelfConformance);
961
922
}
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));
966
923
// Try to rewrite the apply.
967
- return createApplyWithConcreteType (Apply, CEIs , BuilderCtx);
924
+ return createApplyWithConcreteType (Apply, CEI , BuilderCtx);
968
925
}
969
926
970
927
// / Rewrite a protocol extension lookup type from an archetype to a concrete
@@ -979,36 +936,27 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
979
936
// / ==> apply %f<C : P>(%ref)
980
937
SILInstruction *
981
938
SILCombiner::propagateConcreteTypeOfInitExistential (FullApplySite Apply) {
982
- // This optimization requires a generic argument.
983
- if (!Apply.hasSubstitutions ())
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 ())
984
947
return nullptr ;
985
948
986
949
SILBuilderContext BuilderCtx (Builder.getModule (), Builder.getTrackingList ());
987
950
SILOpenedArchetypesTracker OpenedArchetypesTracker (&Builder.getFunction ());
988
951
BuilderCtx.setOpenedArchetypesTracker (&OpenedArchetypesTracker);
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
- }
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 );
1007
957
}
1008
- // Bail, if no argument has a concrete existential to propagate.
1009
- if (CEIs.empty ())
1010
- return nullptr ;
1011
- return createApplyWithConcreteType (Apply, CEIs, BuilderCtx);
958
+ // Perform the transformation by rewriting the apply.
959
+ return createApplyWithConcreteType (Apply, CEI, BuilderCtx);
1012
960
}
1013
961
1014
962
// / \brief Check that all users of the apply are retain/release ignoring one
0 commit comments