Skip to content

Commit 991fe1d

Browse files
committed
RequirementMachine: Preserve replacement paths for redundant rules
1 parent 5404754 commit 991fe1d

File tree

7 files changed

+110
-14
lines changed

7 files changed

+110
-14
lines changed

lib/AST/RequirementMachine/Debug.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ enum class DebugFlags : unsigned {
5959

6060
/// Print debug output from generic signature minimization.
6161
Minimization = (1<<12),
62+
63+
/// Print redundant rules and their replacement paths.
64+
RedundantRules = (1<<13),
65+
66+
/// Print more detail about redundant rules.
67+
RedundantRulesDetail = (1<<14)
6268
};
6369

6470
using DebugOptions = OptionSet<DebugFlags>;

lib/AST/RequirementMachine/HomotopyReduction.cpp

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -420,11 +420,17 @@ findRuleToDelete(llvm::function_ref<bool(unsigned)> isRedundantRuleFn) {
420420
// Homotopy reduction runs multiple passes with different filters to
421421
// prioritize the deletion of certain rules ahead of others. Apply
422422
// the filter now.
423-
if (!isRedundantRuleFn(ruleID))
423+
if (!isRedundantRuleFn(ruleID)) {
424+
if (Debug.contains(DebugFlags::HomotopyReductionDetail)) {
425+
llvm::dbgs() << "** Skipping rule " << rule << " from loop #"
426+
<< pair.first << "\n";
427+
}
428+
424429
continue;
430+
}
425431

426432
if (Debug.contains(DebugFlags::HomotopyReductionDetail)) {
427-
llvm::dbgs() << "** Candidate " << rule << " from loop #"
433+
llvm::dbgs() << "** Candidate rule " << rule << " from loop #"
428434
<< pair.first << "\n";
429435
}
430436

@@ -552,6 +558,12 @@ findRuleToDelete(llvm::function_ref<bool(unsigned)> isRedundantRuleFn) {
552558
/// occurrences of the rule in all loops with the replacement path.
553559
void RewriteSystem::deleteRule(unsigned ruleID,
554560
const RewritePath &replacementPath) {
561+
// Replace all occurrences of the rule with the replacement path in
562+
// all redundant rule paths recorded so far.
563+
for (auto &pair : RedundantRules) {
564+
(void) pair.second.replaceRuleWithPath(ruleID, replacementPath);
565+
}
566+
555567
// Replace all occurrences of the rule with the replacement path in
556568
// all remaining rewrite loops.
557569
for (unsigned loopID : indices(Loops)) {
@@ -573,6 +585,9 @@ void RewriteSystem::deleteRule(unsigned ruleID,
573585
llvm::dbgs() << "\n";
574586
}
575587
}
588+
589+
// Record the redundant rule along with its replacement path.
590+
RedundantRules.emplace_back(ruleID, replacementPath);
576591
}
577592

578593
void RewriteSystem::performHomotopyReduction(
@@ -702,6 +717,26 @@ void RewriteSystem::minimizeRewriteSystem() {
702717
verifyRewriteLoops();
703718
verifyRedundantConformances(redundantConformances);
704719
verifyMinimizedRules(redundantConformances);
720+
721+
if (Debug.contains(DebugFlags::RedundantRules)) {
722+
llvm::dbgs() << "\nRedundant rules:\n";
723+
for (const auto &pair : RedundantRules) {
724+
const auto &rule = getRule(pair.first);
725+
llvm::dbgs() << "- " << rule << " ::== ";
726+
727+
MutableTerm lhs(rule.getLHS());
728+
pair.second.dump(llvm::dbgs(), lhs, *this);
729+
730+
llvm::dbgs() << "\n";
731+
732+
if (Debug.contains(DebugFlags::RedundantRulesDetail)) {
733+
llvm::dbgs() << "\n";
734+
pair.second.dumpLong(llvm::dbgs(), lhs, *this);
735+
736+
llvm::dbgs() << "\n\n";
737+
}
738+
}
739+
}
705740
}
706741

707742
/// In a conformance-valid rewrite system, any rule with unresolved symbols on
@@ -826,6 +861,8 @@ void RewriteSystem::verifyRedundantConformances(
826861
void RewriteSystem::verifyMinimizedRules(
827862
const llvm::DenseSet<unsigned> &redundantConformances) const {
828863
#ifndef NDEBUG
864+
unsigned redundantRuleCount = 0;
865+
829866
for (unsigned ruleID : indices(Rules)) {
830867
const auto &rule = getRule(ruleID);
831868

@@ -845,8 +882,11 @@ void RewriteSystem::verifyMinimizedRules(
845882
continue;
846883
}
847884

885+
if (rule.isRedundant())
886+
++redundantRuleCount;
887+
848888
// LHS-simplified rules should be redundant, unless they're protocol
849-
// conformance rules, which unfortunately might no be redundant, because
889+
// conformance rules, which unfortunately might not be redundant, because
850890
// we try to keep them in the original protocol definition for
851891
// compatibility with the GenericSignatureBuilder's minimization algorithm.
852892
if (rule.isLHSSimplified() &&
@@ -877,5 +917,22 @@ void RewriteSystem::verifyMinimizedRules(
877917
abort();
878918
}
879919
}
920+
921+
if (RedundantRules.size() != redundantRuleCount) {
922+
llvm::errs() << "Expected " << RedundantRules.size() << " redundant rules "
923+
<< "but counted " << redundantRuleCount << "\n";
924+
dump(llvm::errs());
925+
abort();
926+
}
927+
928+
for (const auto &pair : RedundantRules) {
929+
const auto &rule = getRule(pair.first);
930+
if (!rule.isRedundant()) {
931+
llvm::errs() << "Recorded replacement path for non-redundant rule "
932+
<< rule << "\n";
933+
dump(llvm::errs());
934+
abort();
935+
}
936+
}
880937
#endif
881938
}

lib/AST/RequirementMachine/PropertyUnification.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -269,14 +269,14 @@ void PropertyMap::addSuperclassProperty(
269269
recordRelation(key, ruleID, layoutSymbol, System, debug);
270270
}
271271

272-
if (debug) {
273-
llvm::dbgs() << "% New superclass " << superclassDecl->getName()
274-
<< " for " << key << " is ";
275-
}
276-
277272
// If this is the first superclass requirement we've seen for this term,
278273
// just record it and we're done.
279274
if (!props->SuperclassDecl) {
275+
if (debug) {
276+
llvm::dbgs() << "% New superclass " << superclassDecl->getName()
277+
<< " for " << key << "\n";
278+
}
279+
280280
props->SuperclassDecl = superclassDecl;
281281

282282
assert(props->Superclasses.empty());
@@ -290,6 +290,11 @@ void PropertyMap::addSuperclassProperty(
290290
return;
291291
}
292292

293+
if (debug) {
294+
llvm::dbgs() << "% New superclass " << superclassDecl->getName()
295+
<< " for " << key << " is ";
296+
}
297+
293298
// Otherwise, we compare it against the existing superclass requirement.
294299
assert(!props->Superclasses.empty());
295300

lib/AST/RequirementMachine/RewriteContext.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ static DebugOptions parseDebugFlags(StringRef debugFlags) {
4040
.Case("minimal-conformances", DebugFlags::MinimalConformances)
4141
.Case("protocol-dependencies", DebugFlags::ProtocolDependencies)
4242
.Case("minimization", DebugFlags::Minimization)
43+
.Case("redundant-rules", DebugFlags::RedundantRules)
44+
.Case("redundant-rules-detail", DebugFlags::RedundantRulesDetail)
4345
.Default(None);
4446
if (!flag) {
4547
llvm::errs() << "Unknown debug flag in -debug-requirement-machine "

lib/AST/RequirementMachine/RewriteLoop.cpp

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,20 @@ void RewritePath::dump(llvm::raw_ostream &out,
188188
}
189189
}
190190

191+
void RewritePath::dumpLong(llvm::raw_ostream &out,
192+
MutableTerm term,
193+
const RewriteSystem &system) const {
194+
RewritePathEvaluator evaluator(term);
195+
196+
for (const auto &step : Steps) {
197+
evaluator.dump(out);
198+
evaluator.apply(step, system);
199+
out << "\n";
200+
}
201+
202+
evaluator.dump(out);
203+
}
204+
191205
void RewriteLoop::verify(const RewriteSystem &system) const {
192206
#ifndef NDEBUG
193207
RewritePathEvaluator evaluator(Basepoint);
@@ -220,13 +234,17 @@ void RewriteLoop::dump(llvm::raw_ostream &out,
220234
}
221235

222236
void RewritePathEvaluator::dump(llvm::raw_ostream &out) const {
223-
out << "Primary stack:\n";
224-
for (const auto &term : Primary) {
225-
out << term << "\n";
237+
for (unsigned i = 0, e = Primary.size(); i < e; ++i) {
238+
if (i == Primary.size() - 1)
239+
out << "-> ";
240+
else
241+
out << " ";
242+
243+
out << Primary[i] << "\n";
226244
}
227-
out << "\nSecondary stack:\n";
228-
for (const auto &term : Secondary) {
229-
out << term << "\n";
245+
246+
for (unsigned i = 0, e = Secondary.size(); i < e; ++i) {
247+
out << " " << Secondary[Secondary.size() - i - 1] << "\n";
230248
}
231249
}
232250

lib/AST/RequirementMachine/RewriteLoop.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,10 @@ class RewritePath {
409409
void dump(llvm::raw_ostream &out,
410410
MutableTerm term,
411411
const RewriteSystem &system) const;
412+
413+
void dumpLong(llvm::raw_ostream &out,
414+
MutableTerm term,
415+
const RewriteSystem &system) const;
412416
};
413417

414418
/// Information about protocol conformance rules appearing in a rewrite loop.

lib/AST/RequirementMachine/RewriteSystem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,10 @@ class RewriteSystem final {
453453
/// algorithms.
454454
std::vector<RewriteLoop> Loops;
455455

456+
/// A list of pairs where the first element is a rule number and the second
457+
/// element is an equivalent rewrite path in terms of non-redundant rules.
458+
std::vector<std::pair<unsigned, RewritePath>> RedundantRules;
459+
456460
void propagateExplicitBits();
457461

458462
Optional<std::pair<unsigned, unsigned>>

0 commit comments

Comments
 (0)