@@ -574,9 +574,29 @@ void HomotopyGenerator::dump(llvm::raw_ostream &out,
574
574
out << " [deleted]" ;
575
575
}
576
576
577
+ // / Find a rule to delete by looking through all 3-cells for rewrite rules appearing
578
+ // / once in empty context. Returns a redundant rule to delete if one was found,
579
+ // / otherwise returns None.
580
+ // /
581
+ // / Minimization performs three passes over the rewrite system, with the
582
+ // / \p firstPass and \p redundantConformances parameters as follows:
583
+ // /
584
+ // / 1) First, rules involving unresolved name symbols are deleted, with
585
+ // / \p firstPass equal to true and \p redundantConformances equal to nullptr.
586
+ // /
587
+ // / 2) Second, rules that are not conformance rules are deleted, with
588
+ // / \p firstPass equal to false and \p redundantConformances equal to nullptr.
589
+ // /
590
+ // / 3) Finally, conformance rules are deleted after computing a minimal set of
591
+ // / generating conformances, with \p firstPass equal to false and
592
+ // / \p redundantConformances equal to the set of conformance rules that are
593
+ // / not generating conformances.
577
594
Optional<unsigned > RewriteSystem::
578
- findRuleToDelete (RewritePath &replacementPath,
579
- const llvm::DenseSet<unsigned > *redundantConformances) {
595
+ findRuleToDelete (bool firstPass,
596
+ const llvm::DenseSet<unsigned > *redundantConformances,
597
+ RewritePath &replacementPath) {
598
+ assert (!firstPass || redundantConformances == nullptr );
599
+
580
600
for (auto &loop : HomotopyGenerators) {
581
601
if (loop.isDeleted ())
582
602
continue ;
@@ -602,6 +622,13 @@ findRuleToDelete(RewritePath &replacementPath,
602
622
if (rule.isPermanent ())
603
623
return false ;
604
624
625
+ // Other rules involving unresolved name symbols are eliminated in
626
+ // the first pass.
627
+ if (firstPass)
628
+ return rule.containsUnresolvedSymbols ();
629
+
630
+ assert (!rule.containsUnresolvedSymbols ());
631
+
605
632
// Protocol conformance rules are eliminated via a different
606
633
// algorithm which computes "generating conformances".
607
634
if (rule.isProtocolConformanceRule ()) {
@@ -631,6 +658,8 @@ findRuleToDelete(RewritePath &replacementPath,
631
658
return None;
632
659
}
633
660
661
+ // / Delete a rewrite rule that is known to be redundant, replacing all
662
+ // / occurrences of the rule in all 3-cells with the replacement path.
634
663
void RewriteSystem::deleteRule (unsigned ruleID,
635
664
const RewritePath &replacementPath) {
636
665
if (Debug.contains (DebugFlags::HomotopyReduction)) {
@@ -695,19 +724,44 @@ void RewriteSystem::deleteRule(unsigned ruleID,
695
724
}
696
725
}
697
726
727
+ void RewriteSystem::performHomotopyReduction (
728
+ bool firstPass,
729
+ const llvm::DenseSet<unsigned > *redundantConformances) {
730
+ while (true ) {
731
+ RewritePath replacementPath;
732
+ auto optRuleID = findRuleToDelete (firstPass,
733
+ redundantConformances,
734
+ replacementPath);
735
+
736
+ // If there no redundant rules remain in this pass, stop.
737
+ if (!optRuleID)
738
+ return ;
739
+
740
+ deleteRule (*optRuleID, replacementPath);
741
+ }
742
+ }
743
+
698
744
// / Use the 3-cells to delete redundant rewrite rules via a series of Tietze
699
745
// / transformations, updating and simplifying existing 3-cells as each rule
700
746
// / is deleted.
701
747
void RewriteSystem::minimizeRewriteSystem () {
702
- // First, eliminate all redundant rules that are not conformance rules.
703
- while ( true ) {
704
- RewritePath replacementPath;
705
- if (auto optRuleID = findRuleToDelete (replacementPath, nullptr ))
706
- deleteRule (*optRuleID, replacementPath) ;
707
- else
708
- break ;
748
+ // / Begin by normalizing all 3-cells to cyclically-reduced left-canonical
749
+ // / form.
750
+ for ( auto &loop : HomotopyGenerators) {
751
+ if (loop. isDeleted ( ))
752
+ continue ;
753
+
754
+ loop. normalize (* this ) ;
709
755
}
710
756
757
+ // First pass: Eliminate all redundant rules involving unresolved types.
758
+ performHomotopyReduction (/* firstPass=*/ true ,
759
+ /* redundantConformances=*/ nullptr );
760
+
761
+ // Second pass: Eliminate all redundant rules that are not conformance rules.
762
+ performHomotopyReduction (/* firstPass=*/ false ,
763
+ /* redundantConformances=*/ nullptr );
764
+
711
765
// Now find a minimal set of generating conformances.
712
766
//
713
767
// FIXME: For now this just produces a set of redundant conformances, but
@@ -716,15 +770,9 @@ void RewriteSystem::minimizeRewriteSystem() {
716
770
llvm::DenseSet<unsigned > redundantConformances;
717
771
computeGeneratingConformances (redundantConformances);
718
772
719
- // Now, eliminate all redundant conformance rules.
720
- while (true ) {
721
- RewritePath replacementPath;
722
- if (auto optRuleID = findRuleToDelete (replacementPath,
723
- &redundantConformances))
724
- deleteRule (*optRuleID, replacementPath);
725
- else
726
- break ;
727
- }
773
+ // Third pass: Eliminate all redundant conformance rules.
774
+ performHomotopyReduction (/* firstPass=*/ false ,
775
+ /* redundantConformances=*/ &redundantConformances);
728
776
729
777
// Assert if homotopy reduction failed to eliminate a redundant conformance,
730
778
// since this suggests a misunderstanding on my part.
@@ -741,6 +789,29 @@ void RewriteSystem::minimizeRewriteSystem() {
741
789
abort ();
742
790
}
743
791
}
792
+
793
+ // Assert if homotopy reduction failed to eliminate a rewrite rule which was
794
+ // deleted because either it's left hand side can be reduced by some other
795
+ // rule, or because it's right hand side can be reduced further.
796
+ for (const auto &rule : Rules) {
797
+ // Note that sometimes permanent rules can be simplified, but they can never
798
+ // be redundant.
799
+ if (rule.isPermanent ()) {
800
+ if (rule.isRedundant ()) {
801
+ llvm::errs () << " Permanent rule is redundant: " << rule << " \n\n " ;
802
+ dump (llvm::errs ());
803
+ abort ();
804
+ }
805
+
806
+ continue ;
807
+ }
808
+
809
+ if (rule.isSimplified () && !rule.isRedundant ()) {
810
+ llvm::errs () << " Simplified rule is not redundant: " << rule << " \n\n " ;
811
+ dump (llvm::errs ());
812
+ abort ();
813
+ }
814
+ }
744
815
}
745
816
746
817
// / Verify that each 3-cell is a valid loop around its basepoint.
0 commit comments