@@ -70,6 +70,7 @@ void RewriteLoop::recompute(const RewriteSystem &system) {
70
70
Dirty = 0 ;
71
71
72
72
ProjectionCount = 0 ;
73
+ DecomposeCount = 0 ;
73
74
74
75
// Rules appearing in empty context (possibly more than once).
75
76
llvm::SmallDenseSet<unsigned , 2 > rulesInEmptyContext;
@@ -93,9 +94,12 @@ void RewriteLoop::recompute(const RewriteSystem &system) {
93
94
++ProjectionCount;
94
95
break ;
95
96
97
+ case RewriteStep::Decompose:
98
+ ++DecomposeCount;
99
+ break ;
100
+
96
101
case RewriteStep::PrefixSubstitutions:
97
102
case RewriteStep::Shift:
98
- case RewriteStep::Decompose:
99
103
case RewriteStep::Relation:
100
104
case RewriteStep::DecomposeConcrete:
101
105
case RewriteStep::RightConcreteProjection:
@@ -134,6 +138,14 @@ unsigned RewriteLoop::getProjectionCount(
134
138
return ProjectionCount;
135
139
}
136
140
141
+ // / The number of Decompose steps, used by the elimination order to prioritize
142
+ // / loops that are not concrete simplifications.
143
+ unsigned RewriteLoop::getDecomposeCount (
144
+ const RewriteSystem &system) const {
145
+ const_cast <RewriteLoop *>(this )->recompute (system);
146
+ return DecomposeCount;
147
+ }
148
+
137
149
// / If a rewrite loop contains an explicit rule in empty context, propagate the
138
150
// / explicit bit to all other rules appearing in empty context within the same
139
151
// / loop.
@@ -428,56 +440,108 @@ findRuleToDelete(llvm::function_ref<bool(unsigned)> isRedundantRuleFn) {
428
440
const auto &loop = Loops[pair.first ];
429
441
const auto &otherLoop = Loops[found->first ];
430
442
431
- // If one of the rules was a concrete unification projection, prefer to
432
- // eliminate the *other* rule.
433
- //
434
- // For example, if 'X.T == G<U, V>' is implied by the conformance on X,
435
- // and the following three rules are defined in the current protocol:
436
- //
437
- // X.T == G<Int, W>
438
- // X.U == Int
439
- // X.V == W
440
- //
441
- // Then we can either eliminate a) alone, or b) and c). Since b) and c)
442
- // are projections, they are "simpler", and we would rather keep both and
443
- // eliminate a).
444
- unsigned projectionCount = loop.getProjectionCount (*this );
445
- unsigned otherProjectionCount = otherLoop.getProjectionCount (*this );
446
-
447
- if (projectionCount != otherProjectionCount) {
448
- if (projectionCount < otherProjectionCount)
449
- found = pair;
450
-
451
- continue ;
443
+ {
444
+ // If one of the rules was a concrete unification projection, prefer to
445
+ // eliminate the *other* rule.
446
+ //
447
+ // For example, if 'X.T == G<U, V>' is implied by the conformance on X,
448
+ // and the following three rules are defined in the current protocol:
449
+ //
450
+ // a) X.T == G<Int, W>
451
+ // b) X.U == Int
452
+ // c) X.V == W
453
+ //
454
+ // Then we can either eliminate a) alone, or b) and c). Since b) and c)
455
+ // are projections, they are "simpler", and we would rather keep both and
456
+ // eliminate a).
457
+ unsigned projectionCount = loop.getProjectionCount (*this );
458
+ unsigned otherProjectionCount = otherLoop.getProjectionCount (*this );
459
+
460
+ if (projectionCount != otherProjectionCount) {
461
+ if (projectionCount < otherProjectionCount)
462
+ found = pair;
463
+
464
+ continue ;
465
+ }
452
466
}
453
467
454
- // If one of the rules is a concrete type requirement, prefer to
455
- // eliminate the *other* rule.
456
- bool ruleIsConcrete = rule.getLHS ().back ().hasSubstitutions ();
457
- bool otherRuleIsConcrete = otherRule.getLHS ().back ().hasSubstitutions ();
468
+ {
469
+ // If one of the rules is a concrete type requirement, prefer to
470
+ // eliminate the *other* rule.
471
+ bool ruleIsConcrete = rule.getLHS ().back ().hasSubstitutions ();
472
+ bool otherRuleIsConcrete = otherRule.getLHS ().back ().hasSubstitutions ();
458
473
459
- if (ruleIsConcrete != otherRuleIsConcrete) {
460
- if (otherRuleIsConcrete)
461
- found = pair;
474
+ if (ruleIsConcrete != otherRuleIsConcrete) {
475
+ if (otherRuleIsConcrete)
476
+ found = pair;
462
477
463
- continue ;
478
+ continue ;
479
+ }
464
480
}
465
481
466
- // Otherwise, perform a shortlex comparison on (LHS, RHS).
467
- Optional<int > comparison = rule.compare (otherRule, Context);
468
- if (!comparison.hasValue ()) {
469
- // Two rules (T.[C] => T) and (T.[C'] => T) are incomparable if
470
- // C and C' are superclass, concrete type or concrete conformance
471
- // symbols.
472
- found = pair;
473
- continue ;
482
+ {
483
+ // If both are concrete type requirements, prefer to eliminate the
484
+ // one with the more deeply nested type.
485
+ unsigned ruleNesting = rule.getNesting ();
486
+ unsigned otherRuleNesting = otherRule.getNesting ();
487
+
488
+ if (ruleNesting != otherRuleNesting) {
489
+ if (ruleNesting > otherRuleNesting)
490
+ found = pair;
491
+
492
+ continue ;
493
+ }
474
494
}
475
495
476
- if (*comparison > 0 ) {
477
- // Otherwise, if the new rule is less canonical than the best one so
478
- // far, it becomes the new candidate for elimination.
479
- found = pair;
480
- continue ;
496
+ {
497
+ // Otherwise, perform a shortlex comparison on (LHS, RHS).
498
+ Optional<int > comparison = rule.compare (otherRule, Context);
499
+
500
+ if (!comparison.hasValue ()) {
501
+ // Two rules (T.[C] => T) and (T.[C'] => T) are incomparable if
502
+ // C and C' are superclass, concrete type or concrete conformance
503
+ // symbols.
504
+ found = pair;
505
+ continue ;
506
+ }
507
+
508
+ if (*comparison == 0 ) {
509
+ // Given two rewrite loops that both eliminate the same rule, prefer
510
+ // the one that was not recorded by substitution simplification;
511
+ // substitution simplification rules contain the projections in
512
+ // context, which then prevents the projections from being eliminated.
513
+ //
514
+ // An example is if you have two rules implied by conformances on X,
515
+ //
516
+ // a) X.T == G<Y>
517
+ // b) X.T == G<Z>
518
+ //
519
+ // then the induced rule Y == Z is a projection.
520
+ //
521
+ // The rule X.T == G<Z> can be eliminated with a loop that begins at
522
+ // X.T.[concrete: G<Y>] followed by a decomposition and rewrite of
523
+ // Y into Z, finally followed by an inverse decomposition back to
524
+ // X.T.[concrete: G<Z>].
525
+ //
526
+ // However, if we can eliminate G<Y> via some other loop, we prefer
527
+ // to do that, since that might *also* allow us to eliminate Y == Z.
528
+ unsigned decomposeCount = loop.getDecomposeCount (*this );
529
+ unsigned otherDecomposeCount = otherLoop.getDecomposeCount (*this );
530
+
531
+ if (decomposeCount != otherDecomposeCount) {
532
+ if (decomposeCount < otherDecomposeCount)
533
+ found = pair;
534
+
535
+ continue ;
536
+ }
537
+ }
538
+
539
+ if (*comparison > 0 ) {
540
+ // Otherwise, if the new rule is less canonical than the best one so
541
+ // far, it becomes the new candidate for elimination.
542
+ found = pair;
543
+ continue ;
544
+ }
481
545
}
482
546
}
483
547
0 commit comments