I am always wary of saying there might be a compiler bug - usually it is
a bug in the user code. But this time I am very suspicious. The
example here comes from a discussion in the comp.lang.c Usenet group.
Here is the code I have been testing:
unsigned char foo_u(unsigned int v) {
return (v & 0x7f) | (v & ~0x7f ? 0x80 : 0);
}
unsigned char foo_s(int v) {
return (v & 0x7f) | (v & ~0x7f ? 0x80 : 0);
}
unsigned char bar_s(int v) {
int x = v & 0x7f;
return (v & 0x7f) | (x ? 0x80 : 0);
}
int test_u_1(void) {
return foo_u(0x01); // Expect 0x01 = 1
}
int test_u_2(void) {
return foo_u(0x1001); // Expect 0x81 = 129
}
int test_s_1(void) {
return foo_s(0x01); // Expect 0x01 = 1
}
int test_s_2(void) {
return foo_s(0x1001); // Expect 0x81 = 129
}
The assembly code generated for this is:
foo_u(unsigned int):
mov edx, edi
and edx, 127
and edi, -128
cmp edi, 1
sbb eax, eax
not eax
and eax, -128
or eax, edx
ret
foo_s(int):
mov eax, edi
ret
bar_s(int):
mov edx, edi
and edx, 127
and edi, 127
cmp edi, 1
sbb eax, eax
not eax
and eax, -128
or eax, edx
ret
test_u_1():
mov eax, 1
ret
test_u_2():
mov eax, 129
ret
test_s_1():
mov eax, 1
ret
test_s_2():
mov eax, 1
ret
When the code uses "int" rather than "unsigned int", in "foo_s", the
compiler thinks the function can be optimised to a simple byte
extraction. I cannot see how that interpretation is valid. And gcc
cannot see it either, if there is an intermediate variable (in "bar_s").
(The type of the intermediate "x" in "bar_s" does not matter - "int",
"unsigned int", "auto", "__auto_type", const or not).
This effect is happening in the front-end. It is independent of
optimisation levels (-O gives the same results), the target processor (I
tried a half-dozen targets), the compiler version (from gcc 4.4 upwards
- gcc 4.1 gives the same code for foo_s as foo_u. I haven't tried gcc
4.2 or 4.3). The results from the compiler evaluations in the "test_"
functions shows that it this happens in the compiler analysis - it is
not a code generation issue.
<https://godbolt.org> is great for this kind of testing!
Is there something going wrong in gcc here, or is there something I am
missing?
mvh.,
David