[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: