@@ -591,6 +591,42 @@ namespace {
591
591
};
592
592
}
593
593
594
+ // / Update SIL basic block's arguments types which refer to opened
595
+ // / archetypes. Replace such types by performing type substitutions
596
+ // / according to the provided type substitution map.
597
+ static void updateBasicBlockArgTypes (SILBasicBlock *BB,
598
+ TypeSubstitutionMap &TypeSubstMap) {
599
+ // Check types of all BB arguments.
600
+ for (auto &Arg : BB->getBBArgs ()) {
601
+ if (!Arg->getType ().getSwiftRValueType ()->hasOpenedExistential ())
602
+ continue ;
603
+ // Type of this BB argument uses an opened existential.
604
+ // Try to apply substitutions to it and if it produces a different type,
605
+ // use this type as new type of the BB argument.
606
+ auto NewArgType = Arg->getType ().subst (
607
+ BB->getModule (), BB->getModule ().getSwiftModule (), TypeSubstMap);
608
+ if (NewArgType == Arg->getType ())
609
+ continue ;
610
+ // Replace the type of this BB argument. The type of a BBArg
611
+ // can only be changed using replaceBBArg, if the BBArg has no uses.
612
+ // So, make it look as if it has no uses.
613
+
614
+ // First collect all uses, before changing the type.
615
+ SmallVector<Operand *, 4 > OriginalArgUses;
616
+ for (auto *ArgUse : Arg->getUses ()) {
617
+ OriginalArgUses.push_back (ArgUse);
618
+ }
619
+ // Then replace all uses by an undef.
620
+ Arg->replaceAllUsesWith (SILUndef::get (Arg->getType (), BB->getModule ()));
621
+ // Replace the type of the BB argument.
622
+ BB->replaceBBArg (Arg->getIndex (), NewArgType, Arg->getDecl ());
623
+ // Restore all uses to refer to the BB argument with updated type.
624
+ for (auto ArgUse : OriginalArgUses) {
625
+ ArgUse->set (Arg);
626
+ }
627
+ }
628
+ }
629
+
594
630
// / Handle CSE of open_existential_ref instructions.
595
631
// / Returns true if uses of open_existential_ref can
596
632
// / be replaced by a dominating instruction.
@@ -601,6 +637,10 @@ bool CSE::processOpenExistentialRef(SILInstruction *Inst, ValueBase *V,
601
637
SILBasicBlock::iterator &I) {
602
638
assert (isa<OpenExistentialRefInst>(Inst));
603
639
llvm::SmallSetVector<SILInstruction *, 16 > Candidates;
640
+ auto OldOpenedArchetype = getOpenedArchetypeOf (Inst);
641
+ auto NewOpenedArchetype = getOpenedArchetypeOf (dyn_cast<SILInstruction>(V));
642
+ TypeSubstitutionMap TypeSubstMap;
643
+ TypeSubstMap[OldOpenedArchetype.getPointer ()] = NewOpenedArchetype;
604
644
// Collect all candidates that may contain opened archetypes
605
645
// that need to be replaced.
606
646
for (auto Use : Inst->getUses ()) {
@@ -614,10 +654,21 @@ bool CSE::processOpenExistentialRef(SILInstruction *Inst, ValueBase *V,
614
654
}
615
655
Candidates.insert (User);
616
656
}
657
+ if (!isa<TermInst>(User))
658
+ continue ;
659
+ // The current use of the opened archetype is a terminator instruction.
660
+ // Check if any of the successor BBs uses this opened archetype in the
661
+ // types of its basic block arguments. If this is the case, replace
662
+ // those uses by the new opened archetype.
663
+ auto Successors = User->getParent ()->getSuccessorBlocks ();
664
+ for (auto Successor : Successors) {
665
+ if (Successor->bbarg_empty ())
666
+ continue ;
667
+ // If a BB has any arguments, update their types if necessary.
668
+ updateBasicBlockArgTypes (Successor, TypeSubstMap);
669
+ }
617
670
}
618
671
// Now process candidates.
619
- auto OldOpenedArchetype = getOpenedArchetypeOf (Inst);
620
- auto NewOpenedArchetype = getOpenedArchetypeOf (dyn_cast<SILInstruction>(V));
621
672
// TODO: Move it to CSE instance to avoid recreating it every time?
622
673
SILOpenedArchetypesTracker OpenedArchetypesTracker (*Inst->getFunction ());
623
674
// Register the new archetype to be used.
0 commit comments