From e4069ee4fc503e802b1d7f42c0d9c44c37f4ae36 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 7 May 2024 13:25:22 -0500 Subject: [PATCH] Testing LFSR_ATTR as a static inline function I'm committing this temporarily mostly just to record some _very_ interesting code/stack measurements. This explores replacing the LFSR_ATTR macro with an inline function that does the same thing: #define LFSR_ATTR(_tag, _delta, _cat) \ ((const lfsr_attr_t){_tag, _delta, _cat}) vs: #define LFSR_ATTR(_tag, _delta, _cat) \ lfsr_attr(_tag, _delta, _cat) static inline lfsr_attr_t lfsr_attr( lfsr_tag_t tag, lfsr_srid_t delta, lfsr_cat_t cat) { return (lfsr_attr_t){tag, delta, cat}; } The motivation for this is to eventually support more complex lfsr_attr_t layouts. Specifically, it would be nice if we could break up the lfsr_cat_t into separate size/ptr fields. Unfortunately we can't declare temporaries in macros (I wish we had statement expressions), and we really don't want to duplicate the entire cat tree, so an inline function seems like the only way to accomplish this... But static inline functions have the same cost as a macro you say? No. This assumes a perfect compiler. And it's pretty unfair to compiler developers to expect a perfect compiler. To be fair, this is an extremely harsh test. We use LFSR_ATTR _heavily_, which is why it's getting this much scrutiny. lfsr_attr also both takes in a 2-word struct, and returns a _4_-word struct, which probably makes things messy. Still, the results are concerning: code stack macro: 33672 2776 inline: 34512 (+2.5%) 2952 (+6.3%) always_inline: 34512 (+2.5%) 2952 (+6.3%) noinline: 33920 (+0.7%) 2888 (+4.0%) Measured with GCC 11 -mthumb -Os. I also measured with __attribute__((always_inline/noinline)) just to see how that affected things. --- lfs.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lfs.c b/lfs.c index 9c619d6a..e99712ba 100644 --- a/lfs.c +++ b/lfs.c @@ -1567,7 +1567,12 @@ typedef struct lfsr_attr { } lfsr_attr_t; #define LFSR_ATTR(_tag, _delta, _cat) \ - ((const lfsr_attr_t){_tag, _delta, _cat}) + lfsr_attr(_tag, _delta, _cat) + +static inline lfsr_attr_t lfsr_attr( + lfsr_tag_t tag, lfsr_srid_t delta, lfsr_cat_t cat) { + return (lfsr_attr_t){tag, delta, cat}; +} #define LFSR_ATTR_NOOP() LFSR_ATTR(LFSR_TAG_NULL, 0, LFSR_CAT_NULL())