rbyd-rr: Rearranged diverged pruning/trimming after flipping

This was a bit more tricky than the other eager-flip related
transformations, mainly because we have to be careful to not prune the
diverging alt that connects the two diverged trunks. The diverging alt,
i.e. the first alt that diverges, passes all the criteria for pruning,
but is a bit special in that we need to keep it around until we stitch
the trunks together.

I ended up more-or-less just reverting the handling of both-diverging
nodes to being collapsed as a special case of our first encounter with
the diverging alt. Because we eagerly prune, both-diverging nodes can
only happen if they include the diverging alt. We can leveraging this to
simplify our diverging logic a bit, which is already crazy complicated.

Not only does this finish moving all of the alt-related logic into
"flipped space", it also moves all of the diverging logic together,
which is more readable and hopefully leads to better code deduplication
by the compiler.

Long story short, more code savings!

           code          stack
  before: 34244           2864
  after:  34176 (-0.2%)   2864 (+0.0%)

                     code          frame          stack
  appendattr before: 2232            216            568
  appendattr after:  2162 (-3.1%)    208 (-3.7%)    560 (-1.4%)

---

All of these code savings are making our 2-trunk range removal algorithm
more appealing:

                   code          stack
  rr-div-naive:   33968           2864
  rr-div-altn:    34304 (+1.0%)   2864 (+0.0%)
  rr-2trunk-altn: 34176 (+0.6%)   2864 (+0.0%)

                             code           frame           stack
  appendattr rr-stitching:   1940             184             536
  appendattr rr-div-naive:   2028 (+4.5%)     200 (+8.7%)     552 (+3.0%)
  appendattr rr-div-altn:    2198 (+13.3%)    216 (+17.4%)    568 (+6.0%)
  appendattr rr-2trunk-altn: 2162 (+11.4%)    208 (+13.0%)    560 (+4.5%)

That being said, it is getting increasingly hard to compare these
functions. You could argue the eager-flip transformations would also
result in code savings for the earlier iterations of our algorithm,
but it is worth noting the 2-trunk approach _did_ require more flips to
get working, so...
This commit is contained in:
Christopher Haster
2024-04-14 23:59:07 -05:00
parent 00a2332417
commit 94eb672315
+79 -89
View File
@@ -2897,54 +2897,6 @@ trunk:;
LFS_ASSERT(!(lfsr_tag_isred(alt) && lfsr_tag_isred(p[0].alt))
|| lfsr_tag_isparallel(alt, p[0].alt));
// force diverged alts to be pruned
if (diverged
&& lfsr_tag_diverging2(
alt, weight,
p[0].alt, p[0].weight,
lower_rid, upper_rid,
a_rid, a_tag,
b_rid, b_tag)) {
// both diverged? collapse
if (lfsr_tag_isred(p[0].alt)
&& lfsr_tag_diverging(
p[0].alt, p[0].weight,
lower_rid, upper_rid,
a_rid, a_tag,
b_rid, b_tag)) {
if (!lfsr_tag_isparallel(alt, p[0].alt)) {
lfsr_tag_flip2(&alt, &weight,
p[0].alt, p[0].weight,
lower_rid, upper_rid);
lfs_swap32(&jump, &branch_);
}
p[0].alt = alt | LFSR_TAG_R;
p[0].weight += weight;
weight = 0;
// one diverged? trim so alt is pruned
} else {
if (lfsr_tag_follow2(
alt, weight,
p[0].alt, p[0].weight,
lower_rid, upper_rid,
a_rid, a_tag)) {
lfsr_tag_flip2(
&alt, &weight,
p[0].alt, p[0].weight,
lower_rid, upper_rid);
lfs_swap32(&jump, &branch_);
}
lfsr_tag_trim(
alt, weight,
&lower_rid, &upper_rid,
&lower_tag, &upper_tag);
weight = 0;
}
}
// take black alt? needs a flip
// <b >b
// .-'| => .-'|
@@ -2982,6 +2934,85 @@ trunk:;
lfs_swap32(&jump, &branch_);
}
// do bounds want to take different paths? begin diverging
if (!diverged
// diverging black?
&& (lfsr_tag_isblack(alt)
// give up if we find a yellow alt
|| lfsr_tag_isred(p[0].alt))
&& (lfsr_tag_diverging2(
alt, weight,
p[0].alt, p[0].weight,
lower_rid, upper_rid,
a_rid, a_tag,
b_rid, b_tag)
|| (lfsr_tag_isred(p[0].alt)
&& lfsr_tag_diverging(
p[0].alt, p[0].weight,
lower_rid, upper_rid,
a_rid, a_tag,
b_rid, b_tag)))) {
diverged = true;
// both diverged? collapse
if (lfsr_tag_diverging2(
alt, weight,
p[0].alt, p[0].weight,
lower_rid, upper_rid,
a_rid, a_tag,
b_rid, b_tag)
&& (lfsr_tag_isred(p[0].alt)
&& lfsr_tag_diverging(
p[0].alt, p[0].weight,
lower_rid, upper_rid,
a_rid, a_tag,
b_rid, b_tag))) {
LFS_ASSERT(a_rid < b_rid || a_tag < b_tag);
LFS_ASSERT(lfsr_tag_isparallel(alt, p[0].alt));
p[0].alt = alt | LFSR_TAG_R;
p[0].weight += weight;
weight = 0;
}
// diverging upper? stitch together both trunks
if (a_rid > b_rid || a_tag > b_tag) {
lfsr_tag_trim2(
alt, weight,
p[0].alt, p[0].weight,
&lower_rid, &upper_rid,
&lower_tag, &upper_tag);
// stitch together both trunks
err = lfsr_p_push(lfs, rbyd, p,
LFSR_TAG_ALT(LFSR_TAG_LE, LFSR_TAG_B, d_tag),
d_rid - (lower_rid - weight),
jump);
if (err) {
return err;
}
// continue to next alt
branch = branch_;
continue;
}
// force diverged alts to be pruned
} else if (diverged
&& lfsr_tag_diverging2(
alt, weight,
p[0].alt, p[0].weight,
lower_rid, upper_rid,
a_rid, a_tag,
b_rid, b_tag)) {
// one diverged? trim so alt is pruned
lfsr_tag_trim(
alt, weight,
&lower_rid, &upper_rid,
&lower_tag, &upper_tag);
weight = 0;
}
// prune?
// <b >b
// .-'| .-'|
@@ -3027,47 +3058,6 @@ trunk:;
}
}
// do bounds want to take different paths? begin diverging
if (!diverged
// eagerly diverge on lower trunk
&& ((a_rid < b_rid || a_tag < b_tag)
// diverging black?
|| lfsr_tag_isblack(alt)
// give up if we find a yellow alt
|| lfsr_tag_isred(p[0].alt))
// we only need to check the second alt, either
// lower or upper trunk will flip on follow
&& lfsr_tag_diverging2(
alt, weight,
p[0].alt, p[0].weight,
lower_rid, upper_rid,
a_rid, a_tag,
b_rid, b_tag)) {
diverged = true;
// diverging upper? stitch together both trunks
if (a_rid > b_rid || a_tag > b_tag) {
lfsr_tag_trim2(
alt, weight,
p[0].alt, p[0].weight,
&lower_rid, &upper_rid,
&lower_tag, &upper_tag);
// stitch together both trunks
err = lfsr_p_push(lfs, rbyd, p,
LFSR_TAG_ALT(LFSR_TAG_LE, LFSR_TAG_B, d_tag),
d_rid - (lower_rid - weight),
jump);
if (err) {
return err;
}
// continue to next alt
branch = branch_;
continue;
}
}
// two reds makes a yellow, split?
//
// note we've lost the original yellow edge because of flips, but