@@ -605,21 +605,100 @@ SILCombiner::optimizeConcatenationOfStringLiterals(ApplyInst *AI) {
605
605
606
606
// / This routine replaces the old witness method inst with a new one.
607
607
void SILCombiner::replaceWitnessMethodInst (
608
- FullApplySite Apply, WitnessMethodInst *WMI, SILBuilderContext &BuilderCtx,
609
- const CanType &ConcreteType, const ProtocolConformanceRef ConformanceRef) {
608
+ WitnessMethodInst *WMI, SILBuilderContext &BuilderCtx, CanType ConcreteType ,
609
+ const ProtocolConformanceRef ConformanceRef) {
610
610
SILBuilderWithScope WMIBuilder (WMI, BuilderCtx);
611
611
auto *NewWMI = WMIBuilder.createWitnessMethod (
612
612
WMI->getLoc (), ConcreteType, ConformanceRef, WMI->getMember (),
613
613
WMI->getType ());
614
- MutableArrayRef<Operand> Operands = Apply.getInstruction ()->getAllOperands ();
615
- for (auto &Op : Operands) {
616
- if (Op.get () == WMI)
617
- Op.set (NewWMI);
618
- }
614
+ WMI->replaceAllUsesWith (NewWMI);
619
615
if (WMI->use_empty ())
620
616
eraseInstFromFunction (*WMI);
621
617
}
622
618
619
+ // This function propagates concrete type of existential self argument using
620
+ // ProtocolConformanceAnalysis. The concrete type of self can be a class,
621
+ // struct, or an enum. It replaces the witness_method instruction
622
+ // with one that has a concrete type, allowing other optimizations to
623
+ // devirtualize it later.
624
+ SILInstruction *
625
+ SILCombiner::propagateSoleConformingType (FullApplySite Apply,
626
+ WitnessMethodInst *WMI) {
627
+ // If WMI has concrete conformance, it can be optimized.
628
+ if (WMI->getConformance ().isConcrete ())
629
+ return nullptr ;
630
+
631
+ // If the lookup type is an opened existential type,
632
+ // it cannot be made concrete.
633
+ if (!WMI->getLookupType ()->isOpenedExistential ())
634
+ return nullptr ;
635
+
636
+ // If the witness method mutates self, we cannot replace self.
637
+ if (Apply.getOrigCalleeType ()->getSelfParameter ().isIndirectMutating ())
638
+ return nullptr ;
639
+
640
+ // Only applicable in whole-module compilation.
641
+ if (!Apply.getModule ().isWholeModule ())
642
+ return nullptr ;
643
+
644
+ auto *PD = WMI->getLookupProtocol ();
645
+
646
+ // Determine the sole conforming type.
647
+ auto *NTD = PCA->findSoleConformingType (PD);
648
+ if (!NTD)
649
+ return nullptr ;
650
+
651
+ // Sole conforming class should not be open access or have any derived class.
652
+ ClassDecl *CD;
653
+ if ((CD = dyn_cast<ClassDecl>(NTD)) &&
654
+ (CD->getEffectiveAccess () == AccessLevel::Open ||
655
+ CHA->hasKnownDirectSubclasses (CD))) {
656
+ return nullptr ;
657
+ }
658
+
659
+ // Create SIL type for the concrete type.
660
+ auto ElementType = NTD->getDeclaredType ();
661
+ auto ConcreteType = ElementType->getCanonicalType ();
662
+ auto &M = Builder.getModule ();
663
+
664
+ // / Determine OpenedArchetypeDef and SubstituionMap.
665
+ ConcreteExistentialInfo CEI (Apply.getSelfArgumentOperand (), ConcreteType, PD);
666
+ if (!CEI.isValid ())
667
+ return nullptr ;
668
+
669
+ if (!CEI.InitExistential ) {
670
+ // Create SIL type for the concrete type.
671
+ SILType ConcreteSILType = M.Types .getLoweredType (ConcreteType);
672
+
673
+ // Prepare the code by adding UncheckedCast instructions that cast opened
674
+ // existentials to concrete types. Set the ConcreteValue of CEI.
675
+ if (auto *OER = dyn_cast<OpenExistentialRefInst>(CEI.OpenedArchetypeDef )) {
676
+ auto *URCI =
677
+ Builder.createUncheckedRefCast (OER->getLoc (), OER, ConcreteSILType);
678
+ CEI.ConcreteValue = URCI;
679
+ } else if (auto *OEA =
680
+ dyn_cast<OpenExistentialAddrInst>(CEI.OpenedArchetypeDef )) {
681
+ auto *UACI = Builder.createUncheckedAddrCast (
682
+ OEA->getLoc (), OEA, ConcreteSILType.getAddressType ());
683
+ CEI.ConcreteValue = UACI;
684
+ } else {
685
+ llvm_unreachable (
686
+ " Unhandled Argument Type in propagateSoleConformingType" );
687
+ }
688
+ }
689
+
690
+ assert (CEI.ConcreteValue );
691
+
692
+ // / Replace the old WitnessMethod with a new one that has concrete type and
693
+ // / conformance.
694
+ SILBuilderContext BuilderCtx (M, Builder.getTrackingList ());
695
+ replaceWitnessMethodInst (WMI, BuilderCtx, ConcreteType,
696
+ *(CEI.ExistentialSubs .getConformances ().begin ()));
697
+ // / Create the new apply instruction using the concrete type.
698
+ auto *NewAI = createApplyWithConcreteType (Apply, CEI, BuilderCtx);
699
+ return NewAI;
700
+ }
701
+
623
702
// / Given an Apply and an argument value produced by InitExistentialAddrInst,
624
703
// / return true if the argument can be replaced by a copy of its value.
625
704
// /
@@ -799,7 +878,6 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
799
878
if (WMI->getConformance ().isConcrete ())
800
879
return nullptr ;
801
880
802
-
803
881
// If the lookup type is not an opened existential type,
804
882
// it cannot be made more concrete.
805
883
if (!WMI->getLookupType ()->isOpenedExistential ())
@@ -840,7 +918,7 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply,
840
918
// with it.
841
919
if (CEI.ConcreteType != WMI->getLookupType () ||
842
920
SelfConformance != WMI->getConformance ()) {
843
- replaceWitnessMethodInst (Apply, WMI, BuilderCtx, CEI.ConcreteType ,
921
+ replaceWitnessMethodInst (WMI, BuilderCtx, CEI.ConcreteType ,
844
922
SelfConformance);
845
923
}
846
924
// Try to rewrite the apply.
@@ -1101,7 +1179,12 @@ SILInstruction *SILCombiner::visitApplyInst(ApplyInst *AI) {
1101
1179
// (apply (witness_method)) -> propagate information about
1102
1180
// a concrete type from init_existential_addr or init_existential_ref.
1103
1181
if (auto *WMI = dyn_cast<WitnessMethodInst>(AI->getCallee ())) {
1104
- propagateConcreteTypeOfInitExistential (AI, WMI);
1182
+ if (!propagateConcreteTypeOfInitExistential (AI, WMI)) {
1183
+ if (auto *WitnessMethod = dyn_cast<WitnessMethodInst>(AI->getCallee ())) {
1184
+ // Propagate concrete type from ProtocolConformanceAnalysis.
1185
+ propagateSoleConformingType (AI, WitnessMethod);
1186
+ }
1187
+ }
1105
1188
return nullptr ;
1106
1189
}
1107
1190
@@ -1219,10 +1302,16 @@ SILInstruction *SILCombiner::visitTryApplyInst(TryApplyInst *AI) {
1219
1302
if (!AI->getOrigCalleeType ()->isCalleeConsumed ())
1220
1303
return rewriteApplyCallee (AI, TTTFI->getOperand ()).getInstruction ();
1221
1304
}
1305
+
1222
1306
// (apply (witness_method)) -> propagate information about
1223
1307
// a concrete type from init_existential_addr or init_existential_ref.
1224
1308
if (auto *WMI = dyn_cast<WitnessMethodInst>(AI->getCallee ())) {
1225
- propagateConcreteTypeOfInitExistential (AI, WMI);
1309
+ if (!propagateConcreteTypeOfInitExistential (AI, WMI)) {
1310
+ if (auto *WitnessMethod = dyn_cast<WitnessMethodInst>(AI->getCallee ())) {
1311
+ // Propagate concrete type from ProtocolConformanceAnalysis.
1312
+ propagateSoleConformingType (AI, WitnessMethod);
1313
+ }
1314
+ }
1226
1315
return nullptr ;
1227
1316
}
1228
1317
0 commit comments