New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
sys: util: add a sign_extend function #68828
sys: util: add a sign_extend function #68828
Conversation
d830f45
to
9faa7e1
Compare
@fabiobaltieri - would it be ok to request a few unit tests for this function? |
Yeah good point, I'll add some tomorrow, back to draft for now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems very reasonable. FWIW, worth noting that various architectures do this in various ways as a single-instruction primitive (or less, x86 can fold it into a load) instead of a double shift. Are we confident existing compilers optimize that correctly or should we worry about having an override in the toolchain layer? I guess one assumes that if this is how linux does this then gcc and clang are known to get it right?
include/zephyr/sys/util.h
Outdated
* @param value The value to sign expand. | ||
* @param index 0 based bit index to sign bit (0 to 31) | ||
*/ | ||
static inline int32_t sign_extend(int32_t value, int index) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be worth considering redefining as a macro with some __typeof__()
magic to work with arbitrary input word sizes. Because you just know that someone is going to ask for a sign_extend_64().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I tried something like
#define SIGN_EXTEND(value, index) \
(__typeof__(value))(value << (NUM_BITS(value) - 1 - index)) >> (NUM_BITS(value) - 1 - index)
But then realized that I need the signed version of the type, not the same type, for that to work. :-) If you have any idea... meanwhile I've added a 64 bit variants to anticipate that, Linux has it so why not.
9ac1dd1
to
bf41896
Compare
Wow good question, I'd be shocked if there's a chance to optimize it further and it's not done in Linux, my code looks something like this on ARM:
So it looks like it's doing the right thing. |
Funny I found my bug in my driver while trying to figure why that optimization was only showing up once while I was expecting it to be there twice, thanks @andyross. :-) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. If there happens to be another rev for some reason, it would be best to split it into one code commit and one test commit.
Two questions ...
|
bf41896
to
f7e8311
Compare
@peter-mitsis sure, can't think of any reason against either, added few asserts, switched index to uint8_t |
@fabiobaltieri - if you are re-spinning anyway, would it be possible to separate the implementation in the 1st commit, and the test in a 2nd commit? |
f7e8311
to
b30cced
Compare
Yes sorry forgot, split. About the assert, turns out those are unhappy with some tests, I dropped it again for now will look into it later |
Add a sign_extend and sign_extend_64 functions, same as the Linux sign_extend32 and sign_extend64 one. This is useful for sign extending values smaller than 32 bits. Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
Add tests for the sign extend functions. Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
b30cced
to
23cdcf3
Compare
nvm fixed the assert issue and reintroduced again, test split on its own pr |
Pretty much the same as https://elixir.bootlin.com/linux/latest/source/include/linux/bitops.h#L186, figured I would not use the
32
suffix since it works fine for smaller types as well but let me know what you think.Add a sign_extend function, same as the Linux sign_extend32 one. This is useful for sign extending values smaller than 32 bits.