From 0b6e2b243a2b04a0e98187d6e0f5e3e60314adbd Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Thu, 28 Mar 2024 20:36:53 -0500 Subject: [PATCH] rbyd-rr: Fixed unreachable red alts not being pruned It turns out we were never pruning unreachable red alts. I thought we were because of lfsr_tag_prune2 and related logic, but this was custom tailored for the specific unreachable patterns created by yellow splits, and is insufficient for all unreachable alts. Consider this unreachable altbgt 0x300 (the second one): altbgt 0x300 ----------> altbgt 0x300 altrle 0x200 -----.----> altrgt 0x300 <-- unreachable, altbgt 0x300 -----'----> altble 0x200 should have null => tag 0x100 been pruned append tag 0x100 Our prune logic doesn't catch this because the altbgt is pointing a different direction than the altrle we end up taking. This wasn't an issue for earlier range-removal algorithms, since we have a separate explicit check for diverged pruning to avoid weight ambiguity issues. Black altas were also not an issue because this logic does catch unreachable black alts, which are a bit easier. But now that we are emitting intentionally unreachable red alts with the expectation that they will be cleaned up by our pruning logic, this is a bit of a problem... The solution here is to check for unreachable alts after red flips. This duplicates quite a bit of code but avoids the logical complexity of figuring out reachability in all the permutations of red 2-3 nodes. --- lfs.c | 175 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 131 insertions(+), 44 deletions(-) diff --git a/lfs.c b/lfs.c index b3d2554b..36972756 100644 --- a/lfs.c +++ b/lfs.c @@ -934,6 +934,23 @@ static inline bool lfsr_tag_prune2( } } +static inline bool lfsr_tag_unreachable( + lfsr_tag_t alt, lfsr_rid_t weight, + lfsr_srid_t lower_rid, lfsr_srid_t upper_rid, + lfsr_tag_t lower_tag, lfsr_tag_t upper_tag) { + if (lfsr_tag_isgt(alt)) { + return !lfsr_tag_follow( + alt, weight, + lower_rid, upper_rid, + upper_rid-1, upper_tag-1); + } else { + return !lfsr_tag_follow( + alt, weight, + lower_rid, upper_rid, + lower_rid-1, lower_tag+1); + } +} + static inline void lfsr_tag_flip( lfsr_tag_t *alt, lfsr_rid_t *weight, lfsr_srid_t lower, lfsr_srid_t upper) { @@ -2992,7 +3009,7 @@ again:; // red alts we can collapse if (lfsr_tag_isred(p_alts[0])) { - printf("%04x->%04x: rprune 0x%x w%d\n", + printf("%04x->%04x: yrprune 0x%x w%d\n", branch, rbyd->eoff, alt, @@ -3002,7 +3019,7 @@ again:; // black alts just become unreachable, if we pruned these // it would break the coloring of our tree } else { - printf("%04x->%04x: bprune 0x%x w%d\n", + printf("%04x->%04x: ybprune 0x%x w%d\n", branch, rbyd->eoff, alt, @@ -3093,52 +3110,122 @@ again:; } } - // take black alt? needs a flip - // b - // .-'| => .-'| - // 1 2 1 2 1 - if (lfsr_tag_isblack(alt) - && lfsr_tag_follow2( - alt, weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid, - a_rid, a_tag)) { - lfsr_tag_flip2(&alt, &weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid); - lfs_swap32(&jump, &branch_); - } - - // should've taken red alt? needs a flip - // r - // .----'| .-'| - // | | >b - // | .-'| .--|-'| - // 1 2 3 1 2 3 1 - if (lfsr_tag_isred(p_alts[0]) - && lfsr_tag_follow(p_alts[0], p_weights[0], - lower_rid, upper_rid, - a_rid, a_tag)) { - lfs_swap16(&p_alts[0], &alt); - lfs_swap32(&p_weights[0], &weight); - lfs_swap32(&p_jumps[0], &jump); - p_alts[0] |= LFSR_TAG_R; - alt &= ~LFSR_TAG_R; - - lfsr_tag_flip2(&alt, &weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid); - lfs_swap32(&jump, &branch_); - } - + // black alts terminate 2-3-4 nodes if (lfsr_tag_isblack(alt)) { - // trim alts from our current bounds - lfsr_tag_trim2( + // take black alt? needs a flip + // b + // .-'| => .-'| + // 1 2 1 2 1 + if (lfsr_tag_follow2( alt, weight, p_alts[0], p_weights[0], - &lower_rid, &upper_rid, - &lower_tag, &upper_tag); + lower_rid, upper_rid, + a_rid, a_tag)) { + lfsr_tag_flip2(&alt, &weight, + p_alts[0], p_weights[0], + lower_rid, upper_rid); + lfs_swap32(&jump, &branch_); + } + if (lfsr_tag_isred(p_alts[0])) { + // should've taken red alt? needs a flip + // r + // .----'| .-'| + // | | >b + // | .-'| .--|-'| + // 1 2 3 1 2 3 1 + if (lfsr_tag_follow(p_alts[0], p_weights[0], + lower_rid, upper_rid, + a_rid, a_tag)) { + lfs_swap16(&p_alts[0], &alt); + lfs_swap32(&p_weights[0], &weight); + lfs_swap32(&p_jumps[0], &jump); + p_alts[0] |= LFSR_TAG_R; + alt &= ~LFSR_TAG_R; + + lfsr_tag_flip2(&alt, &weight, + p_alts[0], p_weights[0], + lower_rid, upper_rid); + lfs_swap32(&jump, &branch_); + } + + // red unreachable? prune + if (lfsr_tag_unreachable( + p_alts[0], p_weights[0], + lower_rid, upper_rid, + lower_tag, upper_tag)) { + printf("%04x->%04x: rprune 0x%x w%d\n", + branch, + rbyd->eoff, + p_alts[0], + p_weights[0]); + lfsr_tag_trim( + p_alts[0], p_weights[0], + &lower_rid, &upper_rid, + &lower_tag, &upper_tag); + lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps); + + // trim red bounds + } else { + lfsr_tag_trim( + p_alts[0], p_weights[0], + &lower_rid, &upper_rid, + &lower_tag, &upper_tag); + } + } + + // unreachable? + if (lfsr_tag_unreachable( + alt, weight, + lower_rid, upper_rid, + lower_tag, upper_tag)) { + // red unreachable? prune + if (lfsr_tag_isred(p_alts[0])) { + printf("%04x->%04x: brprune 0x%x w%d\n", + branch, + rbyd->eoff, + alt, + weight); + lfsr_tag_trim( + alt, weight, + &lower_rid, &upper_rid, + &lower_tag, &upper_tag); + p_alts[0] &= ~LFSR_TAG_R; + y_branch = branch; + branch = branch_; + continue; + + // black unreachable? collapse to alt-nevers, otherwise + // we risk breaking the coloring of our tree + } else { + printf("%04x->%04x: bprune 0x%x w%d\n", + branch, + rbyd->eoff, + alt, + weight); + lfsr_tag_trim( + alt, weight, + &lower_rid, &upper_rid, + &lower_tag, &upper_tag); + alt = LFSR_TAG_ALT(LFSR_TAG_LE, LFSR_TAG_B, 0); + weight = 0; + jump = 0; + } + // trim black bounds + } else { + lfsr_tag_trim( + alt, weight, + &lower_rid, &upper_rid, + &lower_tag, &upper_tag); + } + +// // trim alts from our current bounds +// lfsr_tag_trim2( +// alt, weight, +// p_alts[0], p_weights[0], +// &lower_rid, &upper_rid, +// &lower_tag, &upper_tag); +// // // keep track of last alt on diverged trunk to stitch the // // trunks together with // if ((d_state == LFSR_D_DIVERGEDLOWER