How can I get GCC to optimize this bit-shifting instruction into a move?
In addition to Booboo's answer, you can try the following which answers your question
How can I get GCC to optimize this into a move?
Just cast each shifted bit-field expression to unsigned short
unsigned short from_half(half h)
{
return (unsigned short)h.mantissa | (unsigned short)(h.exponent << 10) | (unsigned short)(h.sign << 15);
}
https://godbolt.org/z/CfZSgC
It results in:
from_half:
mov eax, edi
ret
Why isn't it optimized that way already?
I am not sure I have a solid answer on this one. Apparently the intermediate promotion of the bit-fields to int
confuses the optimizer... But this is just a guess.
It's been a while since I have coded in C
, but it seems the use of a union
should work:
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
static bool useUnion;
__attribute__ ((__constructor__)) // supported by gcc compiler
static void initUseUnion()
{
union {
uint16_t i;
char c[2];
} n = { 0x0001 };
useUnion = n.c[0]; // little endian
}
typedef struct half
{
unsigned short mantissa:10;
unsigned short exponent:5;
unsigned short sign:1;
} half;
typedef union half_short
{
half h;
uint16_t s;
} half_short;
unsigned short from_half(half h)
{
if (useUnion) {
half_short hs;
hs.h = h;
return hs.s;
}
else {
return h.mantissa | h.exponent << 10 | h.sign << 15;
}
}
half to_half(unsigned short s)
{
if (useUnion) {
half_short hs;
hs.s = s;
return hs.h;
}
else {
half result = { s, s >> 10, s >> 15 };
return result;
}
}
int main(int argc, char* argv[])
{
printf("%d\n", useUnion);
return 0;
}