diff --git a/lfs.c b/lfs.c index 2c3b35d0..955af912 100644 --- a/lfs.c +++ b/lfs.c @@ -884,11 +884,13 @@ static inline bool lfsr_tag_follow( if (lfsr_tag_isgt(alt)) { return rid > upper - (lfsr_srid_t)weight - 1 || (rid == upper - (lfsr_srid_t)weight - 1 - && lfsr_tag_key(tag) > lfsr_tag_key(alt)); + && (lfsr_tag_key(alt) == 0 + || lfsr_tag_key(tag) > lfsr_tag_key(alt))); } else { return rid < lower + (lfsr_srid_t)weight - 1 || (rid == lower + (lfsr_srid_t)weight - 1 - && lfsr_tag_key(tag) <= lfsr_tag_key(alt)); + && (lfsr_tag_key(alt) != 0 + && lfsr_tag_key(tag) <= lfsr_tag_key(alt))); } } @@ -946,14 +948,15 @@ static inline void lfsr_tag_trim( 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) { + LFS_ASSERT((lfsr_srid_t)weight >= 0); if (lfsr_tag_isgt(alt)) { *upper_rid -= weight; - if (upper_tag) { + if (upper_tag && lfsr_tag_key(alt) != 0) { *upper_tag = alt + 1; } } else { *lower_rid += weight; - if (lower_tag) { + if (lower_tag && lfsr_tag_key(alt) != 0) { *lower_tag = alt + 1; } } @@ -2728,6 +2731,8 @@ static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd, return 0; } + printf("%04x->%04x: appendattr:\n", lfsr_rbyd_trunk(rbyd), rbyd->eoff); + // begin appending int err = lfsr_rbyd_prepareappend(lfs, rbyd); if (err) { @@ -2848,12 +2853,20 @@ again:; if (d < 0) { return d; } + printf("%04x->%04x: tag 0x%x w%d (%d %d)\n", + branch, + rbyd->eoff, + alt, + weight, + lower_rid, + upper_rid); // found an alt? if (lfsr_tag_isalt(alt)) { // make jump absolute jump = branch - jump; lfs_size_t branch_ = branch + d; + bool diverged_this_alt = false; // do bounds want to take different paths? begin diverging if (!lfsr_d_isdiverged(d_state) @@ -2878,9 +2891,20 @@ again:; // begin diverging } else { d_state = lfsr_d_diverge(d_state); + printf("%04x->%04x: diverging 0x%x w%d\n", + branch, + rbyd->eoff, + alt, + weight); // stitch together diverged branches if (d_state == LFSR_D_DIVERGEDUPPER && d_tag) { + printf("%04x->%04x: stitching: 0x%x w%d, 0x%x\n", + branch, + rbyd->eoff, + d_tag, + d_rid - lower_rid, + d_branch); err = lfsr_rbyd_p_push(lfs, rbyd, p_alts, p_weights, p_jumps, LFSR_TAG_ALT(LFSR_TAG_LE, LFSR_TAG_B, d_tag), @@ -2890,9 +2914,15 @@ again:; return err; } } + + diverged_this_alt = true; } } +// if (lfsr_d_isdiverged(d_state)) { +// alt &= ~LFSR_TAG_R; +// } + // prune? // b // .-'| .-'| @@ -2936,26 +2966,57 @@ again:; &lower_rid, &upper_rid, &lower_tag, &upper_tag); + // red alts we can collapse if (lfsr_tag_isred(p_alts[0])) { + printf("%04x->%04x: rprune 0x%x w%d\n", + branch, + rbyd->eoff, + alt, + weight); alt = p_alts[0] & ~LFSR_TAG_R; weight = p_weights[0]; jump = p_jumps[0]; lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps); + + // black alts just become unreachable, if we pruned these + // it would break the coloring of our tree } else { - // propagate pruning to yellow splits to avoid issues - // with tail-recursive recoloring - if (lfsr_d_isdiverged(d_state)) { - d_pruned = true; + if (d_state == LFSR_D_DIVERGINGLOWER || diverged_this_alt) { + printf("%04x->%04x: dprune 0x%x w%d\n", + branch, + rbyd->eoff, + alt, + weight); + // propagate pruning to yellow splits to avoid issues + // with tail-recursive recoloring + if (lfsr_d_isdiverged(d_state)) { + d_pruned = true; + } + y_branch = branch; + branch = branch_; + continue; + } else { + printf("%04x->%04x: bprune 0x%x w%d\n", + branch, + rbyd->eoff, + alt, + weight); + alt = LFSR_TAG_ALT(LFSR_TAG_LE, LFSR_TAG_B, 0); + weight = 0; + // jump = 0; } - y_branch = branch; - branch = branch_; - continue; } } // two reds makes a yellow, split? if (lfsr_tag_isred(alt) && lfsr_tag_isred(p_alts[0])) { LFS_ASSERT(lfsr_tag_isparallel(alt, p_alts[0])); + printf("%04x->%04x: ysplit 0x%x w%d 0x%x\n", + branch, + rbyd->eoff, + alt, + weight, + y_branch); // if we take the red or yellow alt we can just point // to the black alt @@ -3016,6 +3077,14 @@ again:; lfsr_rbyd_p_recolor(p_alts, p_weights, p_jumps); } + // keep track of last alt on diverged trunk to stitch the + // trunks together with + if (d_state == LFSR_D_DIVERGEDLOWER + && lfsr_tag_key(p_alts[0]) != 0) { + d_tag = p_alts[0]; + // d_rid = lower_rid; + } + branch = branch_; continue; } @@ -3068,6 +3137,14 @@ again:; &lower_tag, &upper_tag); // no longer pruned d_pruned = false; + + // keep track of last alt on diverged trunk to stitch the + // trunks together with + if (d_state == LFSR_D_DIVERGEDLOWER + && lfsr_tag_key(alt) != 0) { + d_tag = alt; + // d_rid = lower_rid; + } } // push alt onto our queue @@ -3104,7 +3181,7 @@ again:; // keep track of last alt on diverged trunk to stitch the trunks // together with d_state = LFSR_D_DIVERGINGUPPER; - d_tag = p_alts[0]; +// d_tag = p_alts[0]; d_rid = lower_rid; // flush any pending alts @@ -3115,7 +3192,7 @@ again:; } // terminate diverged trunk with an unreachable tag - if (d_tag) { +// if (d_tag) { err = lfsr_rbyd_appendattr_(lfs, rbyd, (lfsr_rbyd_isshrub(rbyd) ? LFSR_TAG_SHRUB : 0) | LFSR_TAG_NULL, @@ -3124,7 +3201,7 @@ again:; if (err) { return err; } - } +// } // swap tag/rid and write out the upper trunk lfs_swap16(&a_tag, &b_tag); diff --git a/scripts/dbgbmap.py b/scripts/dbgbmap.py index 933b1e15..8f31ff98 100755 --- a/scripts/dbgbmap.py +++ b/scripts/dbgbmap.py @@ -813,24 +813,14 @@ class Rbyd: else: alts[j_] |= {'nf': j__, 'c': c} - # prune any alts with unreachable edges - pruned = {} + # treat unreachable alts as converging paths for j_, alt in alts.items(): if 'f' not in alt: - pruned[j_] = alt['nf'] + alt['f'] = alt['nf'] elif 'nf' not in alt: - pruned[j_] = alt['f'] - for j_ in pruned.keys(): - del alts[j_] + alt['nf'] = alt['f'] - for j_, alt in alts.items(): - while alt['f'] in pruned: - alt['f'] = pruned[alt['f']] - while alt['nf'] in pruned: - alt['nf'] = pruned[alt['nf']] - - # find the trunk and depth of each alt, assuming pruned alts - # didn't exist + # find the trunk and depth of each alt def rec_trunk(j_): if j_ not in alts: return trunks[j_] diff --git a/scripts/dbgbtree.py b/scripts/dbgbtree.py index bcc498a6..bc7685ba 100755 --- a/scripts/dbgbtree.py +++ b/scripts/dbgbtree.py @@ -230,10 +230,13 @@ def tagrepr(tag, w, size, off=None): ' w%d' % w if w > 0 else '', size) elif tag & TAG_ALT: - return 'alt%s%s 0x%x w%d %s' % ( + return 'alt%s%s%s w%d %s' % ( 'r' if tag & TAG_R else 'b', - 'gt' if tag & TAG_GT else 'le', - tag & 0x0fff, + 'a' if tag & 0x0fff == 0 and tag & TAG_GT + else 'n' if tag & 0x0fff == 0 + else 'gt' if tag & TAG_GT + else 'le', + ' 0x%x' % (tag & 0x0fff) if tag & 0x0fff != 0 else '', w, '0x%x' % (0xffffffff & (off-size)) if off is not None @@ -473,24 +476,14 @@ class Rbyd: else: alts[j_] |= {'nf': j__, 'c': c} - # prune any alts with unreachable edges - pruned = {} + # treat unreachable alts as converging paths for j_, alt in alts.items(): if 'f' not in alt: - pruned[j_] = alt['nf'] + alt['f'] = alt['nf'] elif 'nf' not in alt: - pruned[j_] = alt['f'] - for j_ in pruned.keys(): - del alts[j_] + alt['nf'] = alt['f'] - for j_, alt in alts.items(): - while alt['f'] in pruned: - alt['f'] = pruned[alt['f']] - while alt['nf'] in pruned: - alt['nf'] = pruned[alt['nf']] - - # find the trunk and depth of each alt, assuming pruned alts - # didn't exist + # find the trunk and depth of each alt def rec_trunk(j_): if j_ not in alts: return trunks[j_] diff --git a/scripts/dbglfs.py b/scripts/dbglfs.py index cd4f2cc0..2c725dcc 100755 --- a/scripts/dbglfs.py +++ b/scripts/dbglfs.py @@ -261,10 +261,13 @@ def tagrepr(tag, w, size, off=None): ' w%d' % w if w > 0 else '', size) elif tag & TAG_ALT: - return 'alt%s%s 0x%x w%d %s' % ( + return 'alt%s%s%s w%d %s' % ( 'r' if tag & TAG_R else 'b', - 'gt' if tag & TAG_GT else 'le', - tag & 0x0fff, + 'a' if tag & 0x0fff == 0 and tag & TAG_GT + else 'n' if tag & 0x0fff == 0 + else 'gt' if tag & TAG_GT + else 'le', + ' 0x%x' % (tag & 0x0fff) if tag & 0x0fff != 0 else '', w, '0x%x' % (0xffffffff & (off-size)) if off is not None @@ -504,24 +507,14 @@ class Rbyd: else: alts[j_] |= {'nf': j__, 'c': c} - # prune any alts with unreachable edges - pruned = {} + # treat unreachable alts as converging paths for j_, alt in alts.items(): if 'f' not in alt: - pruned[j_] = alt['nf'] + alt['f'] = alt['nf'] elif 'nf' not in alt: - pruned[j_] = alt['f'] - for j_ in pruned.keys(): - del alts[j_] + alt['nf'] = alt['f'] - for j_, alt in alts.items(): - while alt['f'] in pruned: - alt['f'] = pruned[alt['f']] - while alt['nf'] in pruned: - alt['nf'] = pruned[alt['nf']] - - # find the trunk and depth of each alt, assuming pruned alts - # didn't exist + # find the trunk and depth of each alt def rec_trunk(j_): if j_ not in alts: return trunks[j_] diff --git a/scripts/dbgmtree.py b/scripts/dbgmtree.py index 07ab0dd9..cce4a8aa 100755 --- a/scripts/dbgmtree.py +++ b/scripts/dbgmtree.py @@ -245,10 +245,13 @@ def tagrepr(tag, w, size, off=None): ' w%d' % w if w > 0 else '', size) elif tag & TAG_ALT: - return 'alt%s%s 0x%x w%d %s' % ( + return 'alt%s%s%s w%d %s' % ( 'r' if tag & TAG_R else 'b', - 'gt' if tag & TAG_GT else 'le', - tag & 0x0fff, + 'a' if tag & 0x0fff == 0 and tag & TAG_GT + else 'n' if tag & 0x0fff == 0 + else 'gt' if tag & TAG_GT + else 'le', + ' 0x%x' % (tag & 0x0fff) if tag & 0x0fff != 0 else '', w, '0x%x' % (0xffffffff & (off-size)) if off is not None @@ -488,24 +491,14 @@ class Rbyd: else: alts[j_] |= {'nf': j__, 'c': c} - # prune any alts with unreachable edges - pruned = {} + # treat unreachable alts as converging paths for j_, alt in alts.items(): if 'f' not in alt: - pruned[j_] = alt['nf'] + alt['f'] = alt['nf'] elif 'nf' not in alt: - pruned[j_] = alt['f'] - for j_ in pruned.keys(): - del alts[j_] + alt['nf'] = alt['f'] - for j_, alt in alts.items(): - while alt['f'] in pruned: - alt['f'] = pruned[alt['f']] - while alt['nf'] in pruned: - alt['nf'] = pruned[alt['nf']] - - # find the trunk and depth of each alt, assuming pruned alts - # didn't exist + # find the trunk and depth of each alt def rec_trunk(j_): if j_ not in alts: return trunks[j_] diff --git a/scripts/dbgrbyd.py b/scripts/dbgrbyd.py index 46d03ebb..c210ece1 100755 --- a/scripts/dbgrbyd.py +++ b/scripts/dbgrbyd.py @@ -232,10 +232,13 @@ def tagrepr(tag, w, size, off=None): ' w%d' % w if w > 0 else '', size) elif tag & TAG_ALT: - return 'alt%s%s 0x%x w%d %s' % ( + return 'alt%s%s%s w%d %s' % ( 'r' if tag & TAG_R else 'b', - 'gt' if tag & TAG_GT else 'le', - tag & 0x0fff, + 'a' if tag & 0x0fff == 0 and tag & TAG_GT + else 'n' if tag & 0x0fff == 0 + else 'gt' if tag & TAG_GT + else 'le', + ' 0x%x' % (tag & 0x0fff) if tag & 0x0fff != 0 else '', w, '0x%x' % (0xffffffff & (off-size)) if off is not None @@ -260,7 +263,8 @@ def dbg_log(data, block_size, rev, eoff, weight, *, if not tag & TAG_ALT: j_ += size - if tag & TAG_ALT: + # skip alt-nevers + if tag & TAG_ALT and tag & ~TAG_R != TAG_ALT: # figure out which alt color if tag & TAG_R: _, ntag, _, _, _ = fromtag(data[j_:]) @@ -692,24 +696,14 @@ def dbg_tree(data, block_size, rev, trunk, weight, *, else: alts[j_] |= {'nf': j__, 'c': c} - # prune any alts with unreachable edges - pruned = {} + # treat unreachable alts as converging paths for j_, alt in alts.items(): if 'f' not in alt: - pruned[j_] = alt['nf'] + alt['f'] = alt['nf'] elif 'nf' not in alt: - pruned[j_] = alt['f'] - for j_ in pruned.keys(): - del alts[j_] + alt['nf'] = alt['f'] - for j_, alt in alts.items(): - while alt['f'] in pruned: - alt['f'] = pruned[alt['f']] - while alt['nf'] in pruned: - alt['nf'] = pruned[alt['nf']] - - # find the trunk and depth of each alt, assuming pruned alts - # didn't exist + # find the trunk and depth of each alt def rec_trunk(j_): if j_ not in alts: return trunks[j_]