Agh, I'm a dumbass - I got leading and trailing mixed up!
For some reason I was associating 'leading' with the least-significant position, because when you're looking at values expressed in conventional binary notation, you start counting bits from the right. I should have checked the GCC documentation, where of course it explicitly says "
Returns the number of leading 0-bits in x, starting at the most significant bit position".
When I use
__builtin_ctz, it does actually work properly.
What I was trying to do was something like this:
#define SOME_REG_VAL_MASK ((uint16_t)0xFFF0)
foo = lookup_table[(PERIPH->SOME_REG & SOME_REG_VAL_MASK) >> __builtin_ctz(SOME_REG_VAL_MASK)];
It was only working accidentally in one place with
__builtin_clz (and a different
uint32_t mask value) because while it was also shifting there too many places and the result was zero, that happened to be the appropriate value at index zero of the array. But in another place with the aforementioned
uint16_t mask, it all went wrong.
For those wondering "why not just add another define with the bit position of the register field?", I'm dealing with third-party headers, and I thought this was a clever solution to use what's already available, because GCC is able to resolve the call to the builtin with a constant argument to a constant value.