@@ -615,91 +615,129 @@ void SILCombiner::replaceWitnessMethodInst(
615
615
eraseInstFromFunction (*WMI);
616
616
}
617
617
618
- // This function propagates concrete type of existential self argument using
618
+ // This function determines concrete type of existential self argument using
619
619
// ProtocolConformanceAnalysis. The concrete type of self can be a class,
620
620
// struct, or an enum. It replaces the witness_method instruction
621
621
// with one that has a concrete type, allowing other optimizations to
622
622
// devirtualize it later.
623
- SILInstruction *
624
- SILCombiner::propagateSoleConformingType (FullApplySite Apply,
625
- WitnessMethodInst *WMI) {
626
- // If WMI has concrete conformance, it can be optimized.
627
- if (WMI->getConformance ().isConcrete ())
628
- return nullptr ;
629
-
630
- // If the lookup type is an opened existential type,
631
- // it cannot be made concrete.
632
- if (!WMI->getLookupType ()->isOpenedExistential ())
633
- return nullptr ;
634
-
635
- // If the witness method mutates self, we cannot replace self.
636
- if (Apply.getOrigCalleeType ()->getSelfParameter ().isIndirectMutating ())
637
- return nullptr ;
638
-
639
- // Only applicable in whole-module compilation.
640
- if (!Apply.getModule ().isWholeModule ())
641
- return nullptr ;
623
+ Optional<ConcreteExistentialInfo>
624
+ SILCombiner::buildConcreteExistentialInfoFromSoleConformingType (
625
+ Operand &ArgOperand) {
626
+ SILInstruction *AI = ArgOperand.getUser ();
627
+ SILModule &M = AI->getModule ();
628
+
629
+ // SoleConformingType is only applicable in whole-module compilation.
630
+ if (!M.isWholeModule ())
631
+ return None;
632
+
633
+ // Determine the protocol.
634
+ ProtocolDecl *PD = nullptr ;
635
+ WitnessMethodInst *WMI = nullptr ;
636
+ FullApplySite FAS = FullApplySite::isa (AI);
637
+ if (FAS && (WMI = dyn_cast<WitnessMethodInst>(FAS.getCallee ())) &&
638
+ (FAS.getSelfArgumentOperand ().get () == ArgOperand.get ())) {
639
+ // If the witness method mutates self, we cannot replace self.
640
+ if (FAS.getOrigCalleeType ()->getSelfParameter ().isIndirectMutating ())
641
+ return None;
642
+ PD = WMI->getLookupProtocol ();
643
+ } else {
644
+ auto ArgType = ArgOperand.get ()->getType ();
645
+ auto SwiftArgType = ArgType.getASTType ();
646
+ if (!ArgType.isExistentialType () || ArgType.isAnyObject () ||
647
+ SwiftArgType->isAny ())
648
+ return None;
649
+ PD = dyn_cast<ProtocolDecl>(SwiftArgType->getAnyNominal ());
650
+ }
642
651
643
- auto *PD = WMI->getLookupProtocol ();
652
+ if (!PD)
653
+ return None;
644
654
645
655
// Determine the sole conforming type.
646
656
auto *NTD = PCA->findSoleConformingType (PD);
647
657
if (!NTD)
648
- return nullptr ;
658
+ return None ;
649
659
650
660
// Sole conforming class should not be open access or have any derived class.
651
661
ClassDecl *CD;
652
662
if ((CD = dyn_cast<ClassDecl>(NTD)) &&
653
663
(CD->getEffectiveAccess () == AccessLevel::Open ||
654
664
CHA->hasKnownDirectSubclasses (CD))) {
655
- return nullptr ;
665
+ return None ;
656
666
}
657
667
658
668
// Create SIL type for the concrete type.
659
669
auto ElementType = NTD->getDeclaredType ();
660
670
auto ConcreteType = ElementType->getCanonicalType ();
661
- auto &M = Builder.getModule ();
662
671
663
672
// / Determine OpenedArchetypeDef and SubstituionMap.
664
- ConcreteExistentialInfo CEI (Apply. getSelfArgumentOperand () , ConcreteType, PD);
665
- if (!CEI .isValid ())
666
- return nullptr ;
673
+ ConcreteExistentialInfo SoleCEI (ArgOperand , ConcreteType, PD);
674
+ if (!SoleCEI .isValid ())
675
+ return None ;
667
676
668
- if (!CEI.InitExistential ) {
677
+ // / Determine the CEI.ConcreteValue.
678
+ if (!SoleCEI.InitExistential ) {
669
679
// Create SIL type for the concrete type.
670
680
SILType ConcreteSILType = M.Types .getLoweredType (ConcreteType);
671
681
672
682
// Prepare the code by adding UncheckedCast instructions that cast opened
673
683
// existentials to concrete types. Set the ConcreteValue of CEI.
674
- if (auto *OER = dyn_cast<OpenExistentialRefInst>(CEI.OpenedArchetypeDef )) {
684
+ if (auto *OER =
685
+ dyn_cast<OpenExistentialRefInst>(SoleCEI.OpenedArchetypeDef )) {
675
686
auto *URCI =
676
687
Builder.createUncheckedRefCast (OER->getLoc (), OER, ConcreteSILType);
677
- CEI .ConcreteValue = URCI;
678
- } else if (auto *OEA =
679
- dyn_cast<OpenExistentialAddrInst>(CEI .OpenedArchetypeDef )) {
688
+ SoleCEI .ConcreteValue = URCI;
689
+ } else if (auto *OEA = dyn_cast<OpenExistentialAddrInst>(
690
+ SoleCEI .OpenedArchetypeDef )) {
680
691
auto *UACI = Builder.createUncheckedAddrCast (
681
692
OEA->getLoc (), OEA, ConcreteSILType.getAddressType ());
682
- CEI .ConcreteValue = UACI;
693
+ SoleCEI .ConcreteValue = UACI;
683
694
} else {
684
- llvm_unreachable (
685
- " Unhandled Argument Type in propagateSoleConformingType" );
695
+ return None;
686
696
}
687
697
}
698
+ return SoleCEI;
699
+ }
700
+ // This function builds a ConcreteExistentialInfo by first following the data
701
+ // flow chain from the ArgOperand. Otherwise, we check if the operand is of
702
+ // protocol type that conforms to a single concrete type.
703
+ Optional<ConcreteExistentialInfo>
704
+ SILCombiner::buildConcreteExistentialInfo (Operand &ArgOperand) {
705
+ // Build a ConcreteExistentialInfo usfollowing the data flow chain of the
706
+ // ArgOperand until the init_existential.
707
+ ConcreteExistentialInfo CEI (ArgOperand);
708
+ if (CEI.isValid ())
709
+ return CEI;
710
+ // Use SoleConformingType information.
711
+ return buildConcreteExistentialInfoFromSoleConformingType (ArgOperand);
712
+ }
688
713
689
- assert (CEI.ConcreteValue );
714
+ // Build ConcreteExistentialInfo for every existential argument of an Apply
715
+ // instruction including Self.
716
+ void SILCombiner::buildConcreteExistentialInfos (
717
+ FullApplySite Apply,
718
+ llvm::SmallDenseMap<unsigned , ConcreteExistentialInfo> &CEIs,
719
+ SILBuilderContext &BuilderCtx,
720
+ SILOpenedArchetypesTracker &OpenedArchetypesTracker) {
721
+ for (unsigned ArgIdx = 0 ; ArgIdx < Apply.getNumArguments (); ArgIdx++) {
722
+ auto ArgASTType = Apply.getArgument (ArgIdx)->getType ().getASTType ();
723
+ if (!ArgASTType->hasArchetype ())
724
+ continue ;
690
725
691
- // / Replace the old WitnessMethod with a new one that has concrete type and
692
- // / conformance.
693
- SILBuilderContext BuilderCtx (M, Builder.getTrackingList ());
694
- replaceWitnessMethodInst (WMI, BuilderCtx, ConcreteType,
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));
700
- // / Create the new apply instruction using the concrete type.
701
- auto *NewAI = createApplyWithConcreteType (Apply, CEIs, BuilderCtx);
702
- return NewAI;
726
+ auto OptionalCEI =
727
+ buildConcreteExistentialInfo (Apply.getArgumentOperands ()[ArgIdx]);
728
+ if (!OptionalCEI.hasValue ())
729
+ continue ;
730
+ auto CEI = OptionalCEI.getValue ();
731
+ assert (CEI.isValid ());
732
+ CEIs.try_emplace (ArgIdx, CEI);
733
+
734
+ if (CEI.ConcreteType ->isOpenedExistential ()) {
735
+ // Temporarily record this opened existential def in this local
736
+ // BuilderContext before rewriting the witness method.
737
+ OpenedArchetypesTracker.addOpenedArchetypeDef (
738
+ cast<ArchetypeType>(CEI.ConcreteType ), CEI.ConcreteTypeDef );
739
+ }
740
+ }
703
741
}
704
742
705
743
// / Given an Apply and an argument value produced by InitExistentialAddrInst,
@@ -933,26 +971,35 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
933
971
if (!WMI->getLookupType ()->isOpenedExistential ())
934
972
return nullptr ;
935
973
936
- // Try to derive the concrete type of self and the related conformance by
937
- // searching for a preceding init_existential.
938
- const ConcreteExistentialInfo CEI (Apply.getSelfArgumentOperand ());
939
- if (!CEI.isValid ())
974
+ // Try to derive the concrete type and the related conformance of self and
975
+ // other existential arguments by searching either for a preceding
976
+ // init_existential or looking up sole conforming type.
977
+ SILBuilderContext BuilderCtx (Builder.getModule (), Builder.getTrackingList ());
978
+ SILOpenedArchetypesTracker OpenedArchetypesTracker (&Builder.getFunction ());
979
+ BuilderCtx.setOpenedArchetypesTracker (&OpenedArchetypesTracker);
980
+ llvm::SmallDenseMap<unsigned , ConcreteExistentialInfo> CEIs;
981
+ buildConcreteExistentialInfos (Apply, CEIs, BuilderCtx,
982
+ OpenedArchetypesTracker);
983
+
984
+ // Bail, if no argument has a concrete existential to propagate.
985
+ if (CEIs.empty ())
940
986
return nullptr ;
987
+ auto SelfCEIIt =
988
+ CEIs.find (Apply.getCalleeArgIndex (Apply.getSelfArgumentOperand ()));
989
+
990
+ // If no SelfCEI is found, then just update the Apply with new CEIs for
991
+ // other arguments.
992
+ if (SelfCEIIt == CEIs.end ())
993
+ return createApplyWithConcreteType (Apply, CEIs, BuilderCtx);
994
+
995
+ auto &SelfCEI = SelfCEIIt->second ;
996
+ assert (SelfCEI.isValid ());
941
997
942
998
// Get the conformance of the init_existential type, which is passed as the
943
999
// self argument, on the witness' protocol.
944
1000
ProtocolConformanceRef SelfConformance =
945
- *CEI .lookupExistentialConformance (WMI->getLookupProtocol ());
1001
+ *SelfCEI .lookupExistentialConformance (WMI->getLookupProtocol ());
946
1002
947
- SILBuilderContext BuilderCtx (Builder.getModule (), Builder.getTrackingList ());
948
- SILOpenedArchetypesTracker OpenedArchetypesTracker (&Builder.getFunction ());
949
- BuilderCtx.setOpenedArchetypesTracker (&OpenedArchetypesTracker);
950
- if (CEI.ConcreteType ->isOpenedExistential ()) {
951
- // Temporarily record this opened existential def in this local
952
- // BuilderContext before rewriting the witness method.
953
- OpenedArchetypesTracker.addOpenedArchetypeDef (
954
- cast<ArchetypeType>(CEI.ConcreteType ), CEI.ConcreteTypeDef );
955
- }
956
1003
// Propagate the concrete type into a callee-operand, which is a
957
1004
// witness_method instruction. It's ok to rewrite the witness method in terms
958
1005
// of a concrete type without rewriting the apply itself. In fact, doing so
@@ -966,15 +1013,12 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
966
1013
// are stuck:
967
1014
// We will re-create the same instruction and re-populate the worklist
968
1015
// with it.
969
- if (CEI .ConcreteType != WMI->getLookupType () ||
1016
+ if (SelfCEI .ConcreteType != WMI->getLookupType () ||
970
1017
SelfConformance != WMI->getConformance ()) {
971
- replaceWitnessMethodInst (WMI, BuilderCtx, CEI .ConcreteType ,
1018
+ replaceWitnessMethodInst (WMI, BuilderCtx, SelfCEI .ConcreteType ,
972
1019
SelfConformance);
973
1020
}
974
- // Construct the map for Self to be used for createApplyWithConcreteType.
975
- llvm::SmallDenseMap<unsigned , ConcreteExistentialInfo> CEIs;
976
- CEIs.insert (std::pair<unsigned , ConcreteExistentialInfo>(
977
- Apply.getCalleeArgIndex (Apply.getSelfArgumentOperand ()), CEI));
1021
+
978
1022
// Try to rewrite the apply.
979
1023
return createApplyWithConcreteType (Apply, CEIs, BuilderCtx);
980
1024
}
@@ -995,27 +1039,16 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply) {
995
1039
if (!Apply.hasSubstitutions ())
996
1040
return nullptr ;
997
1041
1042
+ // Try to derive the concrete type and the related conformance of self and
1043
+ // other existential arguments by searching either for a preceding
1044
+ // init_existential or looking up sole conforming type.
1045
+ llvm::SmallDenseMap<unsigned , ConcreteExistentialInfo> CEIs;
998
1046
SILBuilderContext BuilderCtx (Builder.getModule (), Builder.getTrackingList ());
999
1047
SILOpenedArchetypesTracker OpenedArchetypesTracker (&Builder.getFunction ());
1000
1048
BuilderCtx.setOpenedArchetypesTracker (&OpenedArchetypesTracker);
1001
- llvm::SmallDenseMap<unsigned , ConcreteExistentialInfo> CEIs;
1002
- for (unsigned ArgIdx = 0 ; ArgIdx < Apply.getNumArguments (); ArgIdx++) {
1003
- auto ArgASTType = Apply.getArgument (ArgIdx)->getType ().getASTType ();
1004
- if (!ArgASTType->hasArchetype ())
1005
- continue ;
1006
- const ConcreteExistentialInfo CEI (Apply.getArgumentOperands ()[ArgIdx]);
1007
- if (!CEI.isValid ())
1008
- continue ;
1049
+ buildConcreteExistentialInfos (Apply, CEIs, BuilderCtx,
1050
+ OpenedArchetypesTracker);
1009
1051
1010
- CEIs.insert (std::pair<unsigned , ConcreteExistentialInfo>(ArgIdx, CEI));
1011
-
1012
- if (CEI.ConcreteType ->isOpenedExistential ()) {
1013
- // Temporarily record this opened existential def in this local
1014
- // BuilderContext before rewriting the witness method.
1015
- OpenedArchetypesTracker.addOpenedArchetypeDef (
1016
- cast<ArchetypeType>(CEI.ConcreteType ), CEI.ConcreteTypeDef );
1017
- }
1018
- }
1019
1052
// Bail, if no argument has a concrete existential to propagate.
1020
1053
if (CEIs.empty ())
1021
1054
return nullptr ;
@@ -1241,13 +1274,9 @@ SILInstruction *SILCombiner::visitApplyInst(ApplyInst *AI) {
1241
1274
// (apply (witness_method)) -> propagate information about
1242
1275
// a concrete type from init_existential_addr or init_existential_ref.
1243
1276
if (auto *WMI = dyn_cast<WitnessMethodInst>(AI->getCallee ())) {
1244
- if (!propagateConcreteTypeOfInitExistential (AI, WMI)) {
1245
- if (auto *WitnessMethod = dyn_cast<WitnessMethodInst>(AI->getCallee ())) {
1246
- // Propagate concrete type from ProtocolConformanceAnalysis.
1247
- propagateSoleConformingType (AI, WitnessMethod);
1248
- }
1277
+ if (propagateConcreteTypeOfInitExistential (AI, WMI)) {
1278
+ return nullptr ;
1249
1279
}
1250
- return nullptr ;
1251
1280
}
1252
1281
1253
1282
// (apply (function_ref method_from_protocol_extension)) ->
@@ -1368,13 +1397,9 @@ SILInstruction *SILCombiner::visitTryApplyInst(TryApplyInst *AI) {
1368
1397
// (apply (witness_method)) -> propagate information about
1369
1398
// a concrete type from init_existential_addr or init_existential_ref.
1370
1399
if (auto *WMI = dyn_cast<WitnessMethodInst>(AI->getCallee ())) {
1371
- if (!propagateConcreteTypeOfInitExistential (AI, WMI)) {
1372
- if (auto *WitnessMethod = dyn_cast<WitnessMethodInst>(AI->getCallee ())) {
1373
- // Propagate concrete type from ProtocolConformanceAnalysis.
1374
- propagateSoleConformingType (AI, WitnessMethod);
1375
- }
1400
+ if (propagateConcreteTypeOfInitExistential (AI, WMI)) {
1401
+ return nullptr ;
1376
1402
}
1377
- return nullptr ;
1378
1403
}
1379
1404
1380
1405
// (apply (function_ref method_from_protocol_extension)) ->
0 commit comments