Readopted 16-bit crammed size lfsr_attr_ts

Now that compound-literals have been identified as the culprit, we can
actually adopt this smaller lfsr_attr_t representation without a random
code/stack increase.

This limits lfsr_cat_t's size field to 16-bits (15-bit size + 1-bit
for concatenated datas), allowing simple small attrs (the most common)
to save a word of RAM:

  lfsr_tag_t               lfsr_attr_t
  .---+---.                .---+---+---+---.
  |  tag  |-----------+--->|  tag  |c|size |
  '---+---'           |    +---+---+---+---+
                    .-|--->|     delta     |
  lfsr_srid_t       | |    +---+---+---+---+
  .---+---+---+---. | | .->|      ptr      |
  |     delta     |-' | |  '---+---+---+---'
  '---+---+---+---'   | |
                      | |
  lfsr_cat_t          | |
  .---+---+---+---.   | |
  |c|size |-----------' |
  +---+---+---+---+     |
  |      ptr      |-----'
  '---+---+---+---'

The non-trivial mapping of lfsr_cat_t to lfsr_attr_t does mean a bit
more complexity on lfsr_cat_t access, but now that we figured out the
compound-literal cost it seems the compiler is able to mostly elide
these.

The end result is some nice stack savings:

           code          stack
  before: 33812           2712
  after:  33756 (-0.2%)   2624 (-3.2%)
This commit is contained in:
Christopher Haster
2024-05-09 15:20:05 -05:00
parent 8aebb37b51
commit 85fad999b8
+45 -21
View File
@@ -1416,19 +1416,19 @@ typedef struct lfsr_cat {
// sign(size)=0 => single in-RAM buffer
// sign(size)=1 => multiple concatenated datas
union {
lfs_size_t size;
uint16_t size;
struct {
lfs_size_t size;
uint16_t size;
const uint8_t *buffer;
} buf;
struct {
lfs_size_t size;
uint16_t size;
const lfsr_data_t *datas;
} cat;
} u;
} lfsr_cat_t;
#define LFSR_CAT_ISCAT 0x80000000
#define LFSR_CAT_ISCAT 0x8000
#define LFSR_CAT_NULL() \
((lfsr_cat_t){ \
@@ -1572,8 +1572,14 @@ static int lfsr_bd_progcat(lfs_t *lfs,
typedef struct lfsr_attr {
lfsr_tag_t tag;
uint16_t size;
lfsr_srid_t delta;
lfsr_cat_t cat;
// sign(size)=0 => single in-RAM buffer
// sign(size)=1 => multiple concatenated datas
union {
const uint8_t *buffer;
const lfsr_data_t *datas;
} u;
} lfsr_attr_t;
#define LFSR_ATTR(_tag, _delta, _cat) \
@@ -1584,13 +1590,14 @@ static inline lfsr_attr_t lfsr_attr(
// don't use a compound literal here, GCC hates it
lfsr_attr_t attr;
attr.tag = tag;
attr.size = cat.u.cat.size;
attr.delta = delta;
attr.cat = cat;
attr.u.datas = cat.u.cat.datas;
return attr;
}
#define LFSR_ATTR_NOOP() \
LFSR_ATTR(LFSR_TAG_NULL, 0, LFSR_CAT_NULL())
((const lfsr_attr_t){LFSR_TAG_NULL, 0, LFSR_CAT_NULL()})
// create an attribute list
#define LFSR_ATTRS(...) \
@@ -1604,7 +1611,7 @@ static inline lfsr_attr_t lfsr_attr(
((const lfsr_attr_t){ \
.tag=_tag, \
.delta=_delta, \
.cat.u.buf.buffer=(const void*)(const lfsr_mdir_t*){_mdir}})
.u.buffer=(const void*)(const lfsr_mdir_t*){_mdir}})
// a grm update, note this is mutable! we may update the grm during
// mdir commits
@@ -1612,7 +1619,7 @@ static inline lfsr_attr_t lfsr_attr(
((const lfsr_attr_t){ \
.tag=_tag, \
.delta=_delta, \
.cat.u.buf.buffer=(const void*)(const lfsr_grm_t*){_grm}})
.u.buffer=(const void*)(const lfsr_grm_t*){_grm}})
// writing to an unrelated trunk in the rbyd
typedef struct lfsr_shrubcommit lfsr_shrubcommit_t;
@@ -1621,7 +1628,7 @@ typedef struct lfsr_shrubcommit lfsr_shrubcommit_t;
((const lfsr_attr_t){ \
.tag=_tag, \
.delta=_delta, \
.cat.u.buf.buffer=(const void*)&(const lfsr_shrubcommit_t){ \
.u.buffer=(const void*)&(const lfsr_shrubcommit_t){ \
.shrub=_shrub, \
.rid=_rid, \
.attrs=_attrs, \
@@ -1631,7 +1638,7 @@ typedef struct lfsr_shrubcommit lfsr_shrubcommit_t;
((const lfsr_attr_t){ \
.tag=_tag, \
.delta=_delta, \
.cat.u.buf.buffer=(const void*)(const lfsr_shrub_t*){_shrub}})
.u.buffer=(const void*)(const lfsr_shrub_t*){_shrub}})
// some helpers
static inline bool lfsr_attr_isnoop(const lfsr_attr_t *attr) {
@@ -1642,22 +1649,33 @@ static inline bool lfsr_attr_isinsert(const lfsr_attr_t *attr) {
return !lfsr_tag_isgrow(attr->tag) && attr->delta > 0;
}
static inline lfsr_cat_t lfsr_attr_cat(const lfsr_attr_t *attr) {
lfsr_cat_t cat;
cat.u.cat.size = attr->size;
cat.u.cat.datas = attr->u.datas;
return cat;
}
static inline lfs_size_t lfsr_attr_size(const lfsr_attr_t *attr) {
return lfsr_cat_size(lfsr_attr_cat(attr));
}
static inline lfsr_grm_t *lfsr_attr_grm(const lfsr_attr_t *attr) {
return (lfsr_grm_t*)attr->cat.u.buf.buffer;
return (lfsr_grm_t*)attr->u.buffer;
}
static inline const lfsr_mdir_t *lfsr_attr_mdir(const lfsr_attr_t *attr) {
return (lfsr_mdir_t*)attr->cat.u.buf.buffer;
return (lfsr_mdir_t*)attr->u.buffer;
}
static inline const lfsr_shrubcommit_t *lfsr_attr_shrubcommit(
const lfsr_attr_t *attr) {
return (const lfsr_shrubcommit_t*)attr->cat.u.buf.buffer;
return (const lfsr_shrubcommit_t*)attr->u.buffer;
}
static inline const lfsr_shrub_t *lfsr_attr_shrubtrunk(
const lfsr_attr_t *attr) {
return (const lfsr_shrub_t*)attr->cat.u.buf.buffer;
return (const lfsr_shrub_t*)attr->u.buffer;
}
@@ -3612,7 +3630,7 @@ static int lfsr_rbyd_appendattrs(lfs_t *lfs, lfsr_rbyd_t *rbyd,
&& (lfs_size_t)(rid + 1) <= (lfs_size_t)end_rid) {
int err = lfsr_rbyd_appendattr(lfs, rbyd,
rid - lfs_smax32(start_rid, 0),
attrs[i].tag, attrs[i].delta, attrs[i].cat);
attrs[i].tag, attrs[i].delta, lfsr_attr_cat(&attrs[i]));
if (err) {
return err;
}
@@ -6182,7 +6200,9 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
int err = lfsr_rbyd_appendattr(lfs, &rbyd_,
rid - lfs_smax32(start_rid, 0),
attrs[i].tag, attrs[i].delta, attrs[i].cat);
attrs[i].tag,
attrs[i].delta,
lfsr_attr_cat(&attrs[i]));
if (err) {
return err;
}
@@ -10233,7 +10253,7 @@ static int lfsr_bshrub_commit(lfs_t *lfs, lfsr_file_t *file,
&& !lfsr_tag_isrm(attrs[i].tag)) {
commit_estimate += lfs->attr_estimate;
}
commit_estimate += lfsr_cat_size(attrs[i].cat);
commit_estimate += lfsr_attr_size(&attrs[i]);
}
// does our estimate exceed our shrub_size? need to recalculate an
@@ -11431,7 +11451,10 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
lfsr_attr_t attrs[2];
lfs_size_t attr_count = 0;
lfsr_data_t name_data;
uint8_t buf[LFSR_BTREE_DSIZE];
union {
lfsr_data_t data;
uint8_t buf[LFSR_BTREE_DSIZE];
} data;
// not created yet? need to convert orphan to normal file
if (lfsr_f_isorphan(file->m.flags)) {
@@ -11457,9 +11480,10 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
LFSR_CAT_NULL());
// small file inlined in mdir?
} else if (lfsr_f_isunflush(file->m.flags)) {
data.data = LFSR_DATA_BUF(file->buffer, file->buffer_size);
attrs[attr_count++] = LFSR_ATTR(
LFSR_TAG_SUB | LFSR_TAG_DATA, 0,
LFSR_CAT_BUF(file->buffer, file->buffer_size));
LFSR_CAT_DATA_(&data.data));
// bshrub?
} else if (lfsr_bshrub_isbshrub(&file->m.mdir, &file->bshrub)) {
attrs[attr_count++] = LFSR_ATTR_SHRUBTRUNK(
@@ -11469,7 +11493,7 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
} else if (lfsr_bshrub_isbtree(&file->m.mdir, &file->bshrub)) {
attrs[attr_count++] = LFSR_ATTR(
LFSR_TAG_SUB | LFSR_TAG_BTREE, 0,
LFSR_CAT_BTREE_(&file->bshrub.u.btree, buf));
LFSR_CAT_BTREE_(&file->bshrub.u.btree, data.buf));
} else {
LFS_UNREACHABLE();
}