strange behaviour of -O2 optimization
Hello,
I had a look at the debian bug #225313. This bug only raise raise when
optimization is used. I've submitted a patch, but would like to
understand if gcc behaviour was normal.
I've selected a sample of code that should raise the same issue:
=======================================================================
typedef unsigned long word;
typedef unsigned long long dword;
#define LOW_WORD(x) (word)(x)
#define HIGH_WORD(x) (*(((word *)&(x))+1))
word test(word *A)
{
dword p, u;
p = (dword) A[1];
u = (dword) A[0] - LOW_WORD(p);
A[1] = LOW_WORD(u);
u = (dword) HIGH_WORD(u);
return LOW_WORD(u);
}
int main(int agrc, char **argv)
{
word t[3] = {0,0xFFFFFFFF,0};
return test(t);
}
=======================================================================
Here are the executions of this program with and without optimization:
sh~ gcc -g -O2 -o test test.c
sh~ ./test; echo $?
0
sh~ gcc -g -O0 -o test test.c
sh~ ./test; echo $?
255
And here is the assembler code produced by -O2:
=======================================================================
08048340 <test>:
#define LOW_WORD(x) (word)(x)
#define HIGH_WORD(x) (*(((word *)&(x))+1))
word test(word *A)
{
8048340: 55 push %ebp
8048341: 89 e5 mov %esp,%ebp
8048343: 83 ec 10 sub $0x10,%esp
8048346: 89 75 fc mov %esi,0xfffffffc(%ebp)
8048349: 8b 75 08 mov 0x8(%ebp),%esi
804834c: 89 5d f8 mov %ebx,0xfffffff8(%ebp)
dword p, u;
p = (dword) A[1];
u = (dword) A[0] - LOW_WORD(p);
A[1] = LOW_WORD(u);
u = (dword) HIGH_WORD(u);
804834f: c7 45 f4 00 00 00 00 movl $0x0,0xfffffff4(%ebp)
8048356: 8b 4e 04 mov 0x4(%esi),%ecx
8048359: 8b 06 mov (%esi),%eax
804835b: 29 c8 sub %ecx,%eax
804835d: 89 45 f0 mov %eax,0xfffffff0(%ebp)
8048360: 8b 45 f0 mov 0xfffffff0(%ebp),%eax
8048363: 89 46 04 mov %eax,0x4(%esi)
8048366: 8b 45 f4 mov 0xfffffff4(%ebp),%eax
return LOW_WORD(u);
}
8048369: 8b 5d f8 mov 0xfffffff8(%ebp),%ebx
804836c: 8b 75 fc mov 0xfffffffc(%ebp),%esi
804836f: 89 45 f0 mov %eax,0xfffffff0(%ebp)
8048372: 8b 45 f0 mov 0xfffffff0(%ebp),%eax
8048375: 89 ec mov %ebp,%esp
8048377: 5d pop %ebp
8048378: c3 ret
8048379: 8d b4 26 00 00 00 00 lea 0x0(%esi,1),%esi
=======================================================================
It seems to me that after 'sub %ecx,%eax', the carry is not borrowed
(there is no sbb for the high word of u).
Is this the normal behaviour? Am I missing something? Is the C code
above implicated?
gcc warn about:
test.c: In function `test':
test.c:14: warning: dereferencing type-punned pointer will break
strict-aliasing rules
Is it related?
BTW: I've fixed this by using unions (that permit access to the low and
high words) instead of dwords.
Is there a better solution?
I attach the source code.
TIA,
--
Nekral
typedef unsigned long word;
typedef unsigned long long dword;
#define LOW_WORD(x) (word)(x)
#define HIGH_WORD(x) (*(((word *)&(x))+1))
word test(word *A)
{
dword p, u=0;
p = (dword) A[1];
u = (dword) A[0] - LOW_WORD(p);
A[1] = LOW_WORD(u);
u = (dword) HIGH_WORD(u);
return LOW_WORD(u);
}
int main(int agrc, char **argv)
{
word t[3] = {0,0xFFFFFFFF,0};
return test(t);
}
Reply to: