@@ -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,
@@ -940,26 +978,35 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
940
978
if (!WMI->getLookupType ()->isOpenedExistential ())
941
979
return nullptr ;
942
980
943
- // Try to derive the concrete type of self and the related conformance by
944
- // searching for a preceding init_existential.
945
- const ConcreteExistentialInfo CEI (Apply.getSelfArgumentOperand ());
946
- if (!CEI.isValid ())
981
+ // Try to derive the concrete type and the related conformance of self and
982
+ // other existential arguments by searching either for a preceding
983
+ // init_existential or looking up sole conforming type.
984
+ SILBuilderContext BuilderCtx (Builder.getModule (), Builder.getTrackingList ());
985
+ SILOpenedArchetypesTracker OpenedArchetypesTracker (&Builder.getFunction ());
986
+ BuilderCtx.setOpenedArchetypesTracker (&OpenedArchetypesTracker);
987
+ llvm::SmallDenseMap<unsigned , ConcreteExistentialInfo> CEIs;
988
+ buildConcreteExistentialInfos (Apply, CEIs, BuilderCtx,
989
+ OpenedArchetypesTracker);
990
+
991
+ // Bail, if no argument has a concrete existential to propagate.
992
+ if (CEIs.empty ())
947
993
return nullptr ;
994
+ auto SelfCEIIt =
995
+ CEIs.find (Apply.getCalleeArgIndex (Apply.getSelfArgumentOperand ()));
996
+
997
+ // If no SelfCEI is found, then just update the Apply with new CEIs for
998
+ // other arguments.
999
+ if (SelfCEIIt == CEIs.end ())
1000
+ return createApplyWithConcreteType (Apply, CEIs, BuilderCtx);
1001
+
1002
+ auto &SelfCEI = SelfCEIIt->second ;
1003
+ assert (SelfCEI.isValid ());
948
1004
949
1005
// Get the conformance of the init_existential type, which is passed as the
950
1006
// self argument, on the witness' protocol.
951
1007
ProtocolConformanceRef SelfConformance =
952
- *CEI .lookupExistentialConformance (WMI->getLookupProtocol ());
1008
+ *SelfCEI .lookupExistentialConformance (WMI->getLookupProtocol ());
953
1009
954
- SILBuilderContext BuilderCtx (Builder.getModule (), Builder.getTrackingList ());
955
- SILOpenedArchetypesTracker OpenedArchetypesTracker (&Builder.getFunction ());
956
- BuilderCtx.setOpenedArchetypesTracker (&OpenedArchetypesTracker);
957
- if (CEI.ConcreteType ->isOpenedExistential ()) {
958
- // Temporarily record this opened existential def in this local
959
- // BuilderContext before rewriting the witness method.
960
- OpenedArchetypesTracker.addOpenedArchetypeDef (
961
- cast<ArchetypeType>(CEI.ConcreteType ), CEI.ConcreteTypeDef );
962
- }
963
1010
// Propagate the concrete type into a callee-operand, which is a
964
1011
// witness_method instruction. It's ok to rewrite the witness method in terms
965
1012
// of a concrete type without rewriting the apply itself. In fact, doing so
@@ -973,15 +1020,12 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
973
1020
// are stuck:
974
1021
// We will re-create the same instruction and re-populate the worklist
975
1022
// with it.
976
- if (CEI .ConcreteType != WMI->getLookupType () ||
1023
+ if (SelfCEI .ConcreteType != WMI->getLookupType () ||
977
1024
SelfConformance != WMI->getConformance ()) {
978
- replaceWitnessMethodInst (WMI, BuilderCtx, CEI .ConcreteType ,
1025
+ replaceWitnessMethodInst (WMI, BuilderCtx, SelfCEI .ConcreteType ,
979
1026
SelfConformance);
980
1027
}
981
- // Construct the map for Self to be used for createApplyWithConcreteType.
982
- llvm::SmallDenseMap<unsigned , ConcreteExistentialInfo> CEIs;
983
- CEIs.insert (std::pair<unsigned , ConcreteExistentialInfo>(
984
- Apply.getCalleeArgIndex (Apply.getSelfArgumentOperand ()), CEI));
1028
+
985
1029
// Try to rewrite the apply.
986
1030
return createApplyWithConcreteType (Apply, CEIs, BuilderCtx);
987
1031
}
@@ -1002,27 +1046,16 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply) {
1002
1046
if (!Apply.hasSubstitutions ())
1003
1047
return nullptr ;
1004
1048
1049
+ // Try to derive the concrete type and the related conformance of self and
1050
+ // other existential arguments by searching either for a preceding
1051
+ // init_existential or looking up sole conforming type.
1052
+ llvm::SmallDenseMap<unsigned , ConcreteExistentialInfo> CEIs;
1005
1053
SILBuilderContext BuilderCtx (Builder.getModule (), Builder.getTrackingList ());
1006
1054
SILOpenedArchetypesTracker OpenedArchetypesTracker (&Builder.getFunction ());
1007
1055
BuilderCtx.setOpenedArchetypesTracker (&OpenedArchetypesTracker);
1008
- llvm::SmallDenseMap<unsigned , ConcreteExistentialInfo> CEIs;
1009
- for (unsigned ArgIdx = 0 ; ArgIdx < Apply.getNumArguments (); ArgIdx++) {
1010
- auto ArgASTType = Apply.getArgument (ArgIdx)->getType ().getASTType ();
1011
- if (!ArgASTType->hasArchetype ())
1012
- continue ;
1013
- const ConcreteExistentialInfo CEI (Apply.getArgumentOperands ()[ArgIdx]);
1014
- if (!CEI.isValid ())
1015
- continue ;
1056
+ buildConcreteExistentialInfos (Apply, CEIs, BuilderCtx,
1057
+ OpenedArchetypesTracker);
1016
1058
1017
- CEIs.insert (std::pair<unsigned , ConcreteExistentialInfo>(ArgIdx, CEI));
1018
-
1019
- if (CEI.ConcreteType ->isOpenedExistential ()) {
1020
- // Temporarily record this opened existential def in this local
1021
- // BuilderContext before rewriting the witness method.
1022
- OpenedArchetypesTracker.addOpenedArchetypeDef (
1023
- cast<ArchetypeType>(CEI.ConcreteType ), CEI.ConcreteTypeDef );
1024
- }
1025
- }
1026
1059
// Bail, if no argument has a concrete existential to propagate.
1027
1060
if (CEIs.empty ())
1028
1061
return nullptr ;
@@ -1248,13 +1281,9 @@ SILInstruction *SILCombiner::visitApplyInst(ApplyInst *AI) {
1248
1281
// (apply (witness_method)) -> propagate information about
1249
1282
// a concrete type from init_existential_addr or init_existential_ref.
1250
1283
if (auto *WMI = dyn_cast<WitnessMethodInst>(AI->getCallee ())) {
1251
- if (!propagateConcreteTypeOfInitExistential (AI, WMI)) {
1252
- if (auto *WitnessMethod = dyn_cast<WitnessMethodInst>(AI->getCallee ())) {
1253
- // Propagate concrete type from ProtocolConformanceAnalysis.
1254
- propagateSoleConformingType (AI, WitnessMethod);
1255
- }
1284
+ if (propagateConcreteTypeOfInitExistential (AI, WMI)) {
1285
+ return nullptr ;
1256
1286
}
1257
- return nullptr ;
1258
1287
}
1259
1288
1260
1289
// (apply (function_ref method_from_protocol_extension)) ->
@@ -1375,13 +1404,9 @@ SILInstruction *SILCombiner::visitTryApplyInst(TryApplyInst *AI) {
1375
1404
// (apply (witness_method)) -> propagate information about
1376
1405
// a concrete type from init_existential_addr or init_existential_ref.
1377
1406
if (auto *WMI = dyn_cast<WitnessMethodInst>(AI->getCallee ())) {
1378
- if (!propagateConcreteTypeOfInitExistential (AI, WMI)) {
1379
- if (auto *WitnessMethod = dyn_cast<WitnessMethodInst>(AI->getCallee ())) {
1380
- // Propagate concrete type from ProtocolConformanceAnalysis.
1381
- propagateSoleConformingType (AI, WitnessMethod);
1382
- }
1407
+ if (propagateConcreteTypeOfInitExistential (AI, WMI)) {
1408
+ return nullptr ;
1383
1409
}
1384
- return nullptr ;
1385
1410
}
1386
1411
1387
1412
// (apply (function_ref method_from_protocol_extension)) ->
0 commit comments