Bug 37067 - gcc creating wrong code with -O2
Summary: gcc creating wrong code with -O2
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.3.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-08-09 14:37 UTC by Stefan Brüns
Modified: 2008-08-09 21:07 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Stefan Brüns 2008-08-09 14:37:32 UTC
The following code is producing false results with -O2 optimization (-O1 and O3 are correct):
-------
#include <stdio.h>
#define BLOCK_SIZE 100000

int main()
{
  int i;
  float block_f[BLOCK_SIZE];
  int d_phase = 0;
  int d_phase_inc = 0x100000;

  for (i = 0; i < BLOCK_SIZE; i++){
      block_f[i] = (float)(d_phase);
      d_phase += d_phase_inc;
    }

  printf ("%x %x\n", (int)block_f[1695], (int)block_f[1696]);
  return 0;
}
-----
With -O2, the loop is run only 0x6a0 times, instead of 0x186a0 times.

gcc is from openSUSE 11.0 (4.3.1 20080507 (prerelease) [gcc-4_3-branch revision 135036] (SUSE Linux)), but fc9 is most probably affected as well.

Failing code is a very simplified test case from gnuradio (http://www.ruby-forum.com/topic/156807)
Comment 1 Richard Biener 2008-08-09 18:01:51 UTC
This works for me as far as I can see (you didn't specify the expected
output, and certainly if the loop doesn't run as often as you want you
may print uninitialized memory).  Anyway, if it doesn't work then it is
because d_phase overflows and so invokes undefined behavior.
Comment 2 Stefan Brüns 2008-08-09 20:37:22 UTC
The expected output is quite clear - 69f00000 6a000000 - but output is 69f00000 0.
The loop should run 100000 times, as i does not overflow.
d_phase does overflow after 2048 steps, but this should not influence the loop.

with -O2, gcc seems to do the following:
- d_phase is the same as i*0x100000
- the block should run 0x186a0 times
- (0x186a0 * 0x100000) & 0xffffffff = 0x6a000000
- break when d_phase reaches 0x6a000000 (1696 increment steps)

with -O3 and -O1, d_phase and i get their own variables
there should be at least a warning

Comment 3 Andrew Pinski 2008-08-09 20:42:54 UTC
>The loop should run 100000 times, as i does not overflow.

i does not overflow but d_phase_inc does ...
Comment 4 Richard Biener 2008-08-09 20:43:35 UTC
As I said - it works for me (i686, gcc (Debian 4.3.1-8) 4.3.1).  Still the
overflow invokes undefined behavior and thus _can_ affect the loop.
Comment 5 Andrew Pinski 2008-08-09 20:46:32 UTC
>The loop should run 100000 times, as i does not overflow.

i does not overflow but d_phase does ...

2046 7ff00000
2047 80000000
That is an overflow.

So is:
4094 fff00000
4095 0
Comment 6 Stefan Brüns 2008-08-09 20:56:18 UTC
So is there any possibility to flag a variable to be expected to overflow and "wrap around"? I think there is a lot of code in the wild assuming the loop to run 100000 times and d_phase to overflow all the time, becoming negative.
Comment 7 brian 2008-08-09 21:00:44 UTC
Subject: Re:  gcc creating wrong code with -O2

Just make it unsigned since unsigned overflow is always defined.
Comment 8 Richard Biener 2008-08-09 21:07:33 UTC
You can use -fwrapv.