-O2 math problem on alpha CVS HEAD

Matt Wilson msw@redhat.com
Mon Jun 5 13:15:00 GMT 2000


OK, ladies and gentlemen - I present to you today's Alpha gcc math
puzzler.  I began this from our current development gcc package based
on the 20000521 snapshot.  I've built cc1 from CVS with
--host=alpha-redhat-linux and verified that the code generated is
slightly different, but the same output is produced.  (I only replaced
/usr/lib/gcc-lib/alpha-redhat-linux/2.96/cc1 and ran gcc -O2 test.c -o test)

-- begin test.c

#include <stdio.h>

typedef struct _RenderInfo RenderInfo;
struct _RenderInfo
{
    int y;
    float scaley;
    int src_y;
};

static void
render_image_rgb_a (RenderInfo * info)
{
  int y, ye;
  float error;
  float step;

  y = info->y;
  ye = 256;

  step = 1.0 / info->scaley;

  error = y * step;
  error -= ((int) error) - step;

  for (; y < ye; y++) {
      if (error >= 1.0) {
	  info->src_y += (int) error;
	  error -= (int) error;
	  printf ("src_y = %d\n", info->src_y);
      }
      error += step;
  }
}

int main (void)
{
    RenderInfo info;

    info.y = 0;
    info.src_y = 0;
    info.scaley = 1.0;

    render_image_rgb_a(&info);

    return 0;
}

---- end test.c

With "gcc test.c -o test", we get the correct output of:
src_y = 1
src_y = 2
src_y = 3
src_y = 4
...
src_y = 253
src_y = 254
src_y = 255
src_y = 256

With "gcc -O2 test.c -o test" we get incorrect output of:
src_y = 1
src_y = 3
src_y = 6
src_y = 10
...
src_y = 32131
src_y = 32385
src_y = 32640
src_y = 32896

Clearly in the -O2 case the "error -= (int) error" part of the loop
isn't working.

Here's some fun info:

change the line at the beginning of render_image_rgb_a that says:

  ye = info->y;
to
  ye = 0;

(which is the same value as info->y), the -O2 case works.

Change the line that says:
  step = 1.0 / info->scaley;
to
  step = 1.0;
or
  step = 1.0 / 1.0;

(which assigns the step variable to exacly the same value, given the
values in the info struct), the -O2 case works.

Changing the conditional inside the for loop to read:
      if (error >= 1.0) {
	  int tmp;
	  tmp = (int) error;
	  info->src_y += tmp;
	  error -= (int) error;
	  printf ("src_y = %d\n", info->src_y);
      }

Makes the output look right.

Cheers,

Matt


More information about the Gcc-bugs mailing list