https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96172
Bug ID: 96172
Summary: Failure to optimize direct assignment to bitfield
through shifts
Product: gcc
Version: 11.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: gabravier at gmail dot com
Target Milestone: ---
struct ret_struct
{
union
{
struct
{
unsigned int a : 1;
unsigned int b : 1;
unsigned int c : 1;
};
unsigned char as_char;
};
};
ret_struct f1(uint32_t x)
{
x >>= 16;
ret_struct result;
result.a = x;
result.b = (x >> 1);
result.c = (x >> 2);
return result;
}
// Compiling f1 with GCC yields code equivalent to f2
ret_struct f2(uint32_t x)
{
uint32_t a = (x >> 17) & 1;
uint32_t d = x;
a += a;
x = ((x >> 18) & 1) << 2;
ret_struct result;
result.as_char = ((a | ((d >> 16) & 1)) | x);
return result;
}
// Compiling f2 with GCC yields code equivalent to f3
ret_struct f3(uint32_t x)
{
x >>= 16;
ret_struct result;
result.as_char = (x & 1) | ((x & 2) | (x & 4));
return result;
}
// Compiling f3 with GCC yields code equivalent to f4
ret_struct f4(uint32_t x)
{
ret_struct result;
result.as_char = (x >> 16) & 7;
return result;
}
f1 and f2 can be directly optimized to f4. That transformation is done by LLVM,
but not by GCC.
Additionally, even directly compiling f4 with GCC doesn't yield an optimal code
generation on architectures like x86. GCC generates this :
f4(unsigned int):
shr edi, 16
and edi, 7
xor eax, eax
mov al, dil
ret
and LLVM generates this :
f4(unsigned int):
mov eax, edi
shr eax, 16
and eax, 7
ret