Dropped mode field from lfsr_data_t

Now that in-block fields are limited to 28-bits, we have a few more bits
in our lfsr_data_t size field to encoding things.

This commit uses the top 2-bits to encode one of our 4 different
lfsr_data_t encodings:

- 00--nnnn nnnnnnnn nnnnnnnn nnnnnnnn => buffer poiner
- 01--nnnn nnnnnnnn nnnnnnnn nnnnnnnn => inlined data
- 10--nnnn nnnnnnnn nnnnnnnn nnnnnnnn => on-disk reference
- 11--nnnn nnnnnnnn nnnnnnnn nnnnnnnn => concatenated data pointer
   .--|-------|-------|-------'
   |  |     .-|-------'
   |  |     | '------.
   |  '-----|--------|--------.
   v        v        v        v
  1nnnnnnn 1nnnnnnn 1nnnnnnn 0nnnnnnn <= leb128

Note this still works with a hypothetical 12-bit/10-bit littlefs
variant, where we'd only have 2 spare bits:

- 00nnnnnn nnnnnnnn => buffer poiner
- 01nnnnnn nnnnnnnn => inlined data
- 10nnnnnn nnnnnnnn => on-disk reference
- 11nnnnnn nnnnnnnn => concatenated data pointer
   .|-------'
   |'-------.
   v        v
  1nnnnnnn 0nnnnnnn <= leb128

We don't really care about 8-bit/7-bit, can we even fit an rbyd in a
127-byte block?

The main benefit of this encoding is that lfsr_data_t's pointer fields
get the same space as the two words used to encode on-disk block+off.
This may be useful on systems where ptr=2-word, such as some 16-bit
word/32-bit address devices, and some 2-word CHERI pointer devices.

One interesting thing to note: This encoding is only possible thanks to
the observation that total data size is sufficent information to write
out concatendated datas. We don't really need to know the exact number
until prog time, and during prog we can just iterate over datas until
size is exhausted.

So the size field turns out to be sufficient enough for indicating how
many datas are referenced, saving a data-count field.

Code changes are negligible. It should be noted that _most_ machines
won't benefit from ptr=2-word optimizations, including Thumb, our
benchmark ISA:

           code          stack
  before: 33948           2872
  after:  33912 (-0.1%)   2872 (+0.0%)
This commit is contained in:
Christopher Haster
2024-02-21 00:59:43 -06:00
parent 025788a43c
commit fd85393b54
2 changed files with 27 additions and 36 deletions
+26 -31
View File
@@ -1100,15 +1100,14 @@ static lfs_ssize_t lfsr_bd_progtag(lfs_t *lfs,
/// lfsr_data_t stuff ///
// data uses the size's sign bit to indicate on-disk vs in-device
// the top bits of data's size indicates the actual encoding
// 0x0 => buffer pointer
// 0x4 => inlined data
// 0x8 => on-disk reference
// 0xc => concatenated data pointer
#define LFSR_DATA_ONDISK 0x80000000
// in-device data modes
enum {
LFSR_DATA_BUF = 0,
LFSR_DATA_IMM = 1,
LFSR_DATA_CAT = 2,
};
#define LFSR_DATA_ISIMM 0x40000000
#define LFSR_DATA_ISCAT 0xc0000000
// LFSR_DATA_DATA just provides and escape hatch to pass raw datas
// through the LFSR_ATTR macro
@@ -1117,7 +1116,6 @@ enum {
#define LFSR_DATA_NULL() \
((lfsr_data_t){ \
.u.buf.size=0, \
.u.buf.mode=LFSR_DATA_BUF, \
.u.buf.buffer=NULL})
#define LFSR_DATA_DISK(_block, _off, _size) \
@@ -1129,7 +1127,6 @@ enum {
#define LFSR_DATA_BUF(_buffer, _size) \
((lfsr_data_t){ \
.u.buf.size=_size, \
.u.buf.mode=LFSR_DATA_BUF, \
.u.buf.buffer=(const void*)(_buffer)})
#define LFSR_DATA_IMM(_buffer, _size) \
@@ -1171,52 +1168,48 @@ typedef struct lfsr_shrubcommit lfsr_shrubcommit_t;
((lfsr_data_t){.u.buf.buffer=(const void*)(const lfsr_shrub_t*){_shrub}})
static inline bool lfsr_data_ondisk(const lfsr_data_t *data) {
return data->u.size & LFSR_DATA_ONDISK;
return (data->u.size & LFSR_DATA_ISCAT) == LFSR_DATA_ONDISK;
}
static inline bool lfsr_data_isbuf(const lfsr_data_t *data) {
return !lfsr_data_ondisk(data) && data->u.buf.mode == LFSR_DATA_BUF;
return (data->u.size & LFSR_DATA_ISCAT) == 0;
}
static inline bool lfsr_data_isimm(const lfsr_data_t *data) {
return !lfsr_data_ondisk(data) && data->u.buf.mode == LFSR_DATA_IMM;
return (data->u.size & LFSR_DATA_ISCAT) == LFSR_DATA_ISIMM;
}
static inline bool lfsr_data_iscat(const lfsr_data_t *data) {
return !lfsr_data_ondisk(data) && data->u.buf.mode == LFSR_DATA_CAT;
return (data->u.size & LFSR_DATA_ISCAT) == LFSR_DATA_ISCAT;
}
static inline lfs_size_t lfsr_data_size(const lfsr_data_t *data) {
return data->u.size & ~LFSR_DATA_ONDISK;
return data->u.size & ~LFSR_DATA_ISCAT;
}
// some data initializers just can't be macros, we at least make these inline
// so most of the internal logic is hopefully elided
static inline lfsr_data_t lfsr_data_fromimm(
const void *buffer, lfs_size_t size) {
LFS_ASSERT(size <= 5);
LFS_ASSERT(size <= 8);
lfsr_data_t data;
memcpy(data.u.imm.buf, buffer, size);
data.u.imm.size = size;
data.u.imm.mode = LFSR_DATA_IMM;
data.u.imm.size = LFSR_DATA_ISIMM | size;
return data;
}
static inline lfsr_data_t lfsr_data_fromleb128(uint32_t word) {
lfsr_data_t data;
lfs_ssize_t size = lfs_toleb128(word, data.u.imm.buf, 5);
LFS_ASSERT(size >= 0);
LFS_ASSERT(size > 0);
LFS_ASSERT(size <= 5);
data.u.imm.size = size;
data.u.imm.mode = LFSR_DATA_IMM;
data.u.imm.size = LFSR_DATA_ISIMM | size;
return data;
}
static inline lfsr_data_t lfsr_data_fromcat(
const lfsr_data_t *datas, lfs_size_t count) {
LFS_ASSERT(count <= 255);
// find total size
lfs_size_t size = 0;
for (uint8_t i = 0; i < count; i++) {
@@ -1224,9 +1217,7 @@ static inline lfsr_data_t lfsr_data_fromcat(
}
return (lfsr_data_t){
.u.cat.size=size,
.u.cat.mode=LFSR_DATA_CAT,
.u.cat.count=count,
.u.cat.size=LFSR_DATA_ISCAT | size,
.u.cat.datas=datas};
}
@@ -1257,7 +1248,7 @@ static lfsr_data_t lfsr_data_slice(lfsr_data_t data,
memmove(data.u.imm.buf,
data.u.imm.buf + off_,
size_);
data.u.imm.size = size_;
data.u.imm.size = LFSR_DATA_ISIMM | size_;
// concatenated? not supported
} else {
@@ -1469,7 +1460,7 @@ static int lfsr_bd_progdata_(lfs_t *lfs,
// inlined?
} else if (lfsr_data_isimm(&data)) {
int err = lfsr_bd_prog(lfs, block, off,
data.u.imm.buf, data.u.imm.size,
data.u.imm.buf, lfsr_data_size(&data),
cksum_, flcksum_);
if (err) {
return err;
@@ -1496,14 +1487,18 @@ static int lfsr_bd_progdata(lfs_t *lfs,
// concatenated data? handle specially to avoid recursion
} else {
for (uint8_t i = 0; i < data.u.cat.count; i++) {
int err = lfsr_bd_progdata_(lfs, block, off, data.u.cat.datas[i],
lfs_size_t size = lfsr_data_size(&data);
const lfsr_data_t *datas = data.u.cat.datas;
while (size > 0) {
int err = lfsr_bd_progdata_(lfs, block, off, *datas,
cksum_, flcksum_);
if (err) {
return err;
}
off += lfsr_data_size(&data.u.cat.datas[i]);
off += lfsr_data_size(datas);
size -= lfsr_data_size(datas);
datas += 1;
}
}
+1 -5
View File
@@ -424,18 +424,14 @@ typedef struct lfsr_data {
} disk;
struct {
lfs_ssize_t size;
uint8_t mode;
const uint8_t *buffer;
} buf;
struct {
lfs_ssize_t size;
uint8_t mode;
uint8_t buf[5];
uint8_t buf[8];
} imm;
struct {
lfs_ssize_t size;
uint8_t mode;
uint8_t count;
const struct lfsr_data *datas;
} cat;
} u;