@@ -574,9 +574,29 @@ void HomotopyGenerator::dump(llvm::raw_ostream &out,
574574 out << " [deleted]" ;
575575}
576576
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.
577594Optional<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+
580600 for (auto &loop : HomotopyGenerators) {
581601 if (loop.isDeleted ())
582602 continue ;
@@ -602,6 +622,13 @@ findRuleToDelete(RewritePath &replacementPath,
602622 if (rule.isPermanent ())
603623 return false ;
604624
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+
605632 // Protocol conformance rules are eliminated via a different
606633 // algorithm which computes "generating conformances".
607634 if (rule.isProtocolConformanceRule ()) {
@@ -631,6 +658,8 @@ findRuleToDelete(RewritePath &replacementPath,
631658 return None;
632659}
633660
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.
634663void RewriteSystem::deleteRule (unsigned ruleID,
635664 const RewritePath &replacementPath) {
636665 if (Debug.contains (DebugFlags::HomotopyReduction)) {
@@ -695,19 +724,44 @@ void RewriteSystem::deleteRule(unsigned ruleID,
695724 }
696725}
697726
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+
698744// / Use the 3-cells to delete redundant rewrite rules via a series of Tietze
699745// / transformations, updating and simplifying existing 3-cells as each rule
700746// / is deleted.
701747void 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 ) ;
709755 }
710756
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+
711765 // Now find a minimal set of generating conformances.
712766 //
713767 // FIXME: For now this just produces a set of redundant conformances, but
@@ -716,15 +770,9 @@ void RewriteSystem::minimizeRewriteSystem() {
716770 llvm::DenseSet<unsigned > redundantConformances;
717771 computeGeneratingConformances (redundantConformances);
718772
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);
728776
729777 // Assert if homotopy reduction failed to eliminate a redundant conformance,
730778 // since this suggests a misunderstanding on my part.
@@ -741,6 +789,29 @@ void RewriteSystem::minimizeRewriteSystem() {
741789 abort ();
742790 }
743791 }
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+ }
744815}
745816
746817// / Verify that each 3-cell is a valid loop around its basepoint.
0 commit comments