@@ -74,24 +74,14 @@ void RewriteLoop::recompute(const RewriteSystem &system) {
7474
7575 ProjectionCount = 0 ;
7676 DecomposeCount = 0 ;
77-
78- // Rules appearing in empty context (possibly more than once).
79- llvm::SmallDenseSet<unsigned , 2 > rulesInEmptyContext;
80-
81- // The number of times each rule appears (with or without context).
82- llvm::SmallDenseMap<unsigned , unsigned , 2 > ruleMultiplicity;
77+ Useful = false ;
8378
8479 RewritePathEvaluator evaluator (Basepoint);
85-
8680 for (auto step : Path) {
8781 switch (step.Kind ) {
88- case RewriteStep::Rule: {
89- if (!step.isInContext () && !evaluator.isInContext ())
90- rulesInEmptyContext.insert (step.getRuleID ());
91-
92- ++ruleMultiplicity[step.getRuleID ()];
82+ case RewriteStep::Rule:
83+ Useful |= (!step.isInContext () && !evaluator.isInContext ());
9384 break ;
94- }
9585
9686 case RewriteStep::LeftConcreteProjection:
9787 ++ProjectionCount;
@@ -112,18 +102,7 @@ void RewriteLoop::recompute(const RewriteSystem &system) {
112102 evaluator.apply (step, system);
113103 }
114104
115- Useful = !rulesInEmptyContext.empty ();
116-
117- RulesInEmptyContext.clear ();
118-
119- // Collect all rules that we saw exactly once in empty context.
120- for (auto rule : rulesInEmptyContext) {
121- auto found = ruleMultiplicity.find (rule);
122- assert (found != ruleMultiplicity.end ());
123-
124- if (found->second == 1 )
125- RulesInEmptyContext.push_back (rule);
126- }
105+ RulesInEmptyContext = Path.getRulesInEmptyContext (Basepoint, system);
127106}
128107
129108// / A rewrite rule is redundant if it appears exactly once in a loop
@@ -211,6 +190,46 @@ void RewriteSystem::propagateExplicitBits() {
211190 }
212191}
213192
193+ // / Propagate requirement IDs from redundant rules to their
194+ // / replacements that appear once in empty context.
195+ void RewriteSystem::propagateRedundantRequirementIDs () {
196+ if (Debug.contains (DebugFlags::PropagateRequirementIDs)) {
197+ llvm::dbgs () << " \n Propagating requirement IDs: {" ;
198+ }
199+
200+ for (auto ruleAndReplacement : RedundantRules) {
201+ auto ruleID = ruleAndReplacement.first ;
202+ auto rewritePath = ruleAndReplacement.second ;
203+ auto &rule = Rules[ruleID];
204+
205+ auto requirementID = rule.getRequirementID ();
206+ if (!requirementID.hasValue ())
207+ continue ;
208+
209+ MutableTerm lhs (rule.getLHS ());
210+ for (auto ruleID : rewritePath.getRulesInEmptyContext (lhs, *this )) {
211+ auto &replacement = Rules[ruleID];
212+ if (!replacement.isPermanent () &&
213+ !replacement.getRequirementID ().hasValue ()) {
214+ if (Debug.contains (DebugFlags::PropagateRequirementIDs)) {
215+ llvm::dbgs () << " \n - propagating ID = "
216+ << requirementID
217+ << " \n from " ;
218+ rule.dump (llvm::dbgs ());
219+ llvm::dbgs () << " \n to " ;
220+ replacement.dump (llvm::dbgs ());
221+ }
222+
223+ replacement.setRequirementID (requirementID);
224+ }
225+ }
226+ }
227+
228+ if (Debug.contains (DebugFlags::PropagateRequirementIDs)) {
229+ llvm::dbgs () << " \n }\n " ;
230+ }
231+ }
232+
214233// / After propagating the 'explicit' bit on rules, process pairs of
215234// / conflicting rules, marking one or both of the rules as conflicting,
216235// / which instructs minimization to drop them.
@@ -409,6 +428,51 @@ bool RewritePath::replaceRuleWithPath(unsigned ruleID,
409428 return true ;
410429}
411430
431+ SmallVector<unsigned , 1 >
432+ RewritePath::getRulesInEmptyContext (const MutableTerm &term,
433+ const RewriteSystem &system) {
434+ // Rules appearing in empty context (possibly more than once).
435+ llvm::SmallDenseSet<unsigned , 2 > rulesInEmptyContext;
436+ // The number of times each rule appears (with or without context).
437+ llvm::SmallDenseMap<unsigned , unsigned , 2 > ruleFrequency;
438+
439+ RewritePathEvaluator evaluator (term);
440+ for (auto step : Steps) {
441+ switch (step.Kind ) {
442+ case RewriteStep::Rule: {
443+ if (!step.isInContext () && !evaluator.isInContext ())
444+ rulesInEmptyContext.insert (step.getRuleID ());
445+
446+ ++ruleFrequency[step.getRuleID ()];
447+ break ;
448+ }
449+
450+ case RewriteStep::LeftConcreteProjection:
451+ case RewriteStep::Decompose:
452+ case RewriteStep::PrefixSubstitutions:
453+ case RewriteStep::Shift:
454+ case RewriteStep::Relation:
455+ case RewriteStep::DecomposeConcrete:
456+ case RewriteStep::RightConcreteProjection:
457+ break ;
458+ }
459+
460+ evaluator.apply (step, system);
461+ }
462+
463+ // Collect all rules that we saw exactly once in empty context.
464+ SmallVector<unsigned , 1 > rulesOnceInEmptyContext;
465+ for (auto rule : rulesInEmptyContext) {
466+ auto found = ruleFrequency.find (rule);
467+ assert (found != ruleFrequency.end ());
468+
469+ if (found->second == 1 )
470+ rulesOnceInEmptyContext.push_back (rule);
471+ }
472+
473+ return rulesOnceInEmptyContext;
474+ }
475+
412476// / Find a rule to delete by looking through all loops for rewrite rules appearing
413477// / once in empty context. Returns a pair consisting of a loop ID and a rule ID,
414478// / otherwise returns None.
@@ -654,7 +718,7 @@ void RewriteSystem::performHomotopyReduction(
654718
655719 // If no redundant rules remain which can be eliminated by this pass, stop.
656720 if (!optPair)
657- return ;
721+ break ;
658722
659723 unsigned loopID = optPair->first ;
660724 unsigned ruleID = optPair->second ;
@@ -679,6 +743,8 @@ void RewriteSystem::performHomotopyReduction(
679743
680744 deleteRule (ruleID, replacementPath);
681745 }
746+
747+ propagateRedundantRequirementIDs ();
682748}
683749
684750void RewriteSystem::normalizeRedundantRules () {
0 commit comments