Skip to content

Commit a0c3045

Browse files
committed
RequirementMachine: Relax criterion for deleting a useless loop
Distinguish a loop with elimination candidates, which are rules appearing in empty context and exactly once, from a useful loop, which contains at least one rule in empty context (but the same rule might appear more than once). Normalizing a useful loop might produce a loop with elimination candidates, but normalizing a useless loop never does.
1 parent 713e0a4 commit a0c3045

File tree

2 files changed

+33
-17
lines changed

2 files changed

+33
-17
lines changed

lib/AST/RequirementMachine/HomotopyReduction.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@
6464
using namespace swift;
6565
using namespace rewriting;
6666

67-
/// Recompute RulesInEmptyContext and DecomposeCount if needed.
67+
/// Recompute Useful, RulesInEmptyContext, ProjectionCount and DecomposeCount
68+
/// if needed.
6869
void RewriteLoop::recompute(const RewriteSystem &system) {
6970
if (!Dirty)
7071
return;
@@ -110,6 +111,8 @@ void RewriteLoop::recompute(const RewriteSystem &system) {
110111
evaluator.apply(step, system);
111112
}
112113

114+
Useful = !rulesInEmptyContext.empty();
115+
113116
RulesInEmptyContext.clear();
114117

115118
// Collect all rules that we saw exactly once in empty context.
@@ -147,6 +150,14 @@ unsigned RewriteLoop::getDecomposeCount(
147150
return DecomposeCount;
148151
}
149152

153+
/// The number of Decompose steps, used by the elimination order to prioritize
154+
/// loops that are not concrete simplifications.
155+
bool RewriteLoop::isUseful(
156+
const RewriteSystem &system) const {
157+
const_cast<RewriteLoop *>(this)->recompute(system);
158+
return Useful;
159+
}
160+
150161
/// If a rewrite loop contains an explicit rule in empty context, propagate the
151162
/// explicit bit to all other rules appearing in empty context within the same
152163
/// loop.
@@ -419,22 +430,21 @@ findRuleToDelete(llvm::function_ref<bool(unsigned)> isRedundantRuleFn) {
419430
if (loop.isDeleted())
420431
continue;
421432

422-
bool foundAny = false;
423-
for (unsigned ruleID : loop.findRulesAppearingOnceInEmptyContext(*this)) {
424-
redundancyCandidates.emplace_back(loopID, ruleID);
425-
foundAny = true;
426-
}
427-
428433
// Delete loops that don't contain any rewrite rules in empty context,
429-
// since such loops do not give us useful information.
430-
if (!foundAny) {
434+
// since such loops do not yield any elimination candidates.
435+
if (!loop.isUseful(*this)) {
431436
if (Debug.contains(DebugFlags::HomotopyReduction)) {
432437
llvm::dbgs() << "** Deleting useless loop #" << loopID << ": ";
433438
loop.dump(llvm::dbgs(), *this);
434439
llvm::dbgs() << "\n";
435440
}
436441

437442
loop.markDeleted();
443+
continue;
444+
}
445+
446+
for (unsigned ruleID : loop.findRulesAppearingOnceInEmptyContext(*this)) {
447+
redundancyCandidates.emplace_back(loopID, ruleID);
438448
}
439449
}
440450

lib/AST/RequirementMachine/RewriteLoop.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -454,12 +454,18 @@ class RewriteLoop {
454454
/// Cached value for getDecomposeCount().
455455
unsigned DecomposeCount : 15;
456456

457-
/// Loops are deleted once they no longer contain rules in empty context,
458-
/// since at that point they don't participate in minimization and do not
459-
/// need to be considered.
457+
/// A useful loop contains at least one rule in empty context, even if that
458+
/// rule appears multiple times or also in non-empty context. The only loops
459+
/// that are elimination candidates contain a rule in empty context *exactly
460+
/// once*. A useful loop can become an elimination candidate after
461+
/// normalization.
462+
unsigned Useful : 1;
463+
464+
/// Loops are deleted once they are no longer useful, as defined above.
460465
unsigned Deleted : 1;
461466

462-
/// If true, RulesInEmptyContext should be recomputed.
467+
/// If true, Useful, RulesInEmptyContext, ProjectionCount, and DecomposeCount
468+
/// should be recomputed.
463469
unsigned Dirty : 1;
464470

465471
void recompute(const RewriteSystem &system);
@@ -469,11 +475,11 @@ class RewriteLoop {
469475
: Basepoint(basepoint), Path(path) {
470476
ProjectionCount = 0;
471477
DecomposeCount = 0;
472-
478+
Useful = 0;
473479
Deleted = 0;
474480

475-
// Initially, RulesInEmptyContext and ProjectionCount are not valid because
476-
// they have not been computed yet.
481+
// Initially, cached values are not valid because they have not been
482+
// computed yet.
477483
Dirty = 1;
478484
}
479485

@@ -491,7 +497,7 @@ class RewriteLoop {
491497
Dirty = 1;
492498
}
493499

494-
bool isInContext(const RewriteSystem &system) const;
500+
bool isUseful(const RewriteSystem &system) const;
495501

496502
ArrayRef<unsigned>
497503
findRulesAppearingOnceInEmptyContext(const RewriteSystem &system) const;

0 commit comments

Comments
 (0)