Reworked lfsr_data_t based on what functionality we actually use

- Ripped out outdated file-data representation. We don't need this.

- Changed lfsr_data_add/read/cmp to just assert when data is
  concatenated data. Theoretically this is possible to implement, but
  it's complicated and we never use it, so all it is is a waste of
  code size...

- Added implicitly zero-filled hole representation, though this isn't
  adopted in the code yet.

- Added lfsr_data_truncate/fruncate, these are really useful for
  shrub/tree carving/coalescing.

---

New lfsr_data_t encoding, sign(size) indicates if the data is
on-disk/in-device, and a mode field indicates how in-device data should
be parsed:

  sign(size)=1 => on-disk:

    .---+---+---+---.          .....
    |1|   size      |      ..''     ''..
    +---+---+---+---+     :    :        :
    |     block ------+->|            ..:|
    +---+---+---+---+ |  |......( )::::::|
    |      off -------'  |:::'    :      |
    '---+---+---+---'     :'       :    :
                           ''..     :.''
                               '''''

  sign(size)=0, mode=0 => in-device buffer:

    .---+---+---+---.   .---+---+---+---.
    |0|   size      | .>| data...       |
    +---+---+---+---+ | '       .       '
    |m=0|           | | '       .       '
    +---+---+---+---+ | '               '
    |      ptr -------' '               '
    '---+---+---+---'   '---+---+---+---'

  sign(size)=0, mode=1 => hole

    .---+---+---+---.
    |0|   size      |
    +---+---+---+---+
    |m=1|           |
    +---+           +
    |               |
    '---+---+---+---'

  sign(size)=0, mode=2 => inlined

    .---+---+---+---.
    |0|   size      |
    +---+---+---+---+
    |m=2| inlined d |
    +---+           +
    | ata...        |
    '---+---+---+---'

  sign(size)=0, mode=3 => concatenated datas:

    .---+---+---+---.   .---+---+---+---.
    |0|   size      | .>|     data      |
    +---+---+---+---+ | +               +
    |m=3| c |       | | |               |
    +---+---+---+---+ | +               +
    |      ptr -------' |               |
    '---+---+---+---'   +---+---+---+---+
                        |     data      |
                        +               +
                        |               |
                        +               +
                        |               |
                        +---+---+---+---+
                        '       .       '
                        '       .       '
                        '       .       '
                        '               '
                        '               '
                        '---+---+---+---'

---

Code/RAM changes:

            code          stack
  before:  31952           2056
  after:   31396 (-1.7%)   2064 (+0.4%)

I think the increased RAM cost is due to lfsr_data_add/truncate/fruncate
passing lfsr_data_t around by value, and GCC not being able to optimize
this very well since it's 3 words.  I think most move optimizations stop
after 2-words...
This commit is contained in:
Christopher Haster
2023-10-25 23:27:10 -05:00
parent 36e8f01261
commit 13192f3f6b
2 changed files with 254 additions and 451 deletions
+36 -36
View File
@@ -446,52 +446,52 @@ typedef struct lfs_mdir {
lfs_block_t tail[2];
} lfs_mdir_t;
// either an on-disk or in-device data pointer
// Either an on-disk or in-device data pointer
//
// The sign-bit of the size field indicates if the data is
// in-device or on-disk.
//
// After removing the sign bit, the size always encodes the
// resulting size on-disk.
//
// The exact representation of in-device data also depends on the
// mode field:
// - pointer to a RAM-backed buffer
// - implicitly zero-filled holes
// - inlined data able to fit at least 1 leb128
// - an array of concatenated datas
//
// Note concatenated datas can only be 1 level deep. Concatenating
// concatenated datas would require recursion to resolve.
//
typedef struct lfsr_data {
union {
// The sign-bit of the size field indicates if the data is in-device
// or on-disk.
//
// After removing the sign bit, the size always encodes the resulting
// size on-disk.
//
// After this the count field indicates the in-device representation,
// which has a few forms:
// - count == 0 => data inlined in data struct
// - count == 1 => direct pointer to data
// - count >= 2 => indirect pointer to array of datas
//
// The indirect pointer can point to inlined/direct datas or even
// on-disk datas, but not more indirect datas as that would require
// recursion.
//
lfs_ssize_t size;
struct {
lfs_ssize_t size;
uint8_t count;
uint8_t buf[5];
} inlined;
struct {
lfs_ssize_t size;
uint8_t count;
const uint8_t *buffer;
} direct;
struct {
lfs_ssize_t size;
uint8_t count;
const struct lfsr_data *datas;
} indirect;
struct {
lfs_ssize_t size;
lfs_block_t block;
lfs_size_t off;
} disk;
// TODO doc
struct {
lfs_ssize_t size;
lfs_off_t pos;
const struct lfsr_file *file;
} file;
uint8_t mode;
const uint8_t *buffer;
} buf;
struct {
lfs_ssize_t size;
uint8_t mode;
} hole;
struct {
lfs_ssize_t size;
uint8_t mode;
uint8_t buf[5];
} imm;
struct {
lfs_ssize_t size;
uint8_t mode;
uint8_t count;
const struct lfsr_data *datas;
} cat;
} u;
} lfsr_data_t;