Bug 28045 - [4.0/4.1 Regression] Bitfield, &&, and optimization => bad code generation
Summary: [4.0/4.1 Regression] Bitfield, &&, and optimization => bad code generation
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.1.1
: P3 normal
Target Milestone: 4.0.4
Assignee: Richard Biener
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2006-06-15 19:12 UTC by Jerry James
Modified: 2014-02-16 13:16 UTC (History)
4 users (show)

See Also:
Host: x86_64-redhat-linux
Target: x86_64-redhat-linux
Build: x86_64-redhat-linux
Known to work: 3.4.0
Known to fail: 4.0.0 4.1.0 4.2.0
Last reconfirmed: 2006-06-18 10:58:42


Attachments
Testcase showing an optimizaton bug (5.64 KB, text/plain)
2006-06-17 21:04 UTC, Jerry James
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jerry James 2006-06-15 19:12:03 UTC
This is a stripped-down bit of code representing a bad code generation problem we've been having with XEmacs 21.5 + gcc 4.X + optimization.  I can reproduce with Fedora Core 5's packaging of gcc 4.1.1 on the x86_64 platform, and with Ubuntu's packaging of gcc 4.0.3 on the i386 platform.

Compile the following code without optimization, and it reports that the negation of 1 is -1, which is in bounds.  Compile with any -O flag (confirmed for -O, -O2, -O3, and -Os) and the code reports that the negation of 1 is -1, which is out of bounds.  If I break the && expression up into 2 consecutive if statements to see which bound is supposedly violated, the optimized code reports that -1 is within each bound individually.

Things that have no effect: int/long are interchangeable; the size of the "tag" bitfield doesn't seem to matter, so long as the "tag" size and the "val" size add up to "INT_BITS".

I also tried compiling with all of the flags turned on by -O, but without -O itself.  Good code is generated in that case.

#include <stdio.h>

#define INT_BITS (sizeof(int) * 8)
#define MAX_VALUE (int)((1UL << (INT_BITS - 2)) - 1UL)
#define MIN_VALUE (-MAX_VALUE - 1)

struct tagged_int
{
  int tag: 2;
  int val: INT_BITS - 2;
};

static void
negate (struct tagged_int accum)
{
  printf ("min = %d, max = %d\n", MIN_VALUE, MAX_VALUE);
  printf ("The negation of 1 is %d, which is ", -(int)accum.val);
  if (-(int)accum.val <= MAX_VALUE && -(int)accum.val >= MIN_VALUE) {
    puts ("in bounds.");
  } else {
    puts ("out of bounds.");
  }
}

int
main ()
{
  struct tagged_int obj;

  obj.tag = 0;
  obj.val = 1L;
  negate(obj);
  return 0;
}
Comment 1 Richard Biener 2006-06-15 20:04:41 UTC
Works for me on the mainline.
Comment 2 Jerry James 2006-06-17 21:04:29 UTC
Created attachment 11688 [details]
Testcase showing an optimizaton bug
Comment 3 Jerry James 2006-06-17 21:05:09 UTC
I can confirm that both the mainline and the current 4.1 branch compile the testcase correctly.  Nevertheless, both the current 4.1 branch and the mainline (revision 114741) are still miscompiling XEmacs when any optimization at all is used, so the testcase must be too simple.  I just attached a more complex testcase that includes much of the actual code from XEmacs.  I trimmed this down quite a bit from the original code, but it's still over 600 lines.  This code illustrates the bug on both the i386 and x86_64 platforms.  You have to link with the GMP library (-lgmp) when compiling.
Comment 4 Andrew Pinski 2006-06-17 22:06:49 UTC
Reduced testcase:
struct a
{
   unsigned int bits : 1;
   signed long val : ((sizeof(long) * 8) - 1);
};
int Fnegate (struct a b)
{
  if ((-((long)b.val)) <= ((long) ((1UL << (((sizeof(long) * 8) - 1) - 1)) -1UL)) && (-((long)b.val)) >= (-(((long) ((1UL << (((sizeof(long) * 8) - 1) - 1)) -1UL))) - 1))
     return 0 ;
     abort ();
}
int main ()
{
  struct a b = {1, 1};
  Fnegate (b);
  return 0;
}
Comment 5 Richard Biener 2006-06-18 10:58:42 UTC
operand_equal_p (bD.1525.valD.1524, (long intD.2) bD.1525.valD.1524, 0)

is true.  make_range preserved the cast to (long int) for a reason, though.

If we fix operand_equal_p, we no longer fold the test, but keep

  if (-(long int) b.val <= 1073741823 && -(long int) b.val >= -1073741824)
    {
      return 0;
    }
  abort ();

so, I have a patch.
Comment 6 Richard Biener 2006-06-19 14:48:56 UTC
Subject: Bug 28045

Author: rguenth
Date: Mon Jun 19 14:48:47 2006
New Revision: 114772

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=114772
Log:
2006-06-19  Richard Guenther  <rguenther@suse.de>

	PR middle-end/28045
	* fold-const.c (operand_equal_p): Check if the argument types
	have the same precision before stripping NOPs.

	* gcc.dg/torture/pr28045.c: New testcase.

Added:
    trunk/gcc/testsuite/gcc.dg/torture/pr28045.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/fold-const.c
    trunk/gcc/testsuite/ChangeLog

Comment 7 Richard Biener 2006-06-19 14:49:08 UTC
Fixed on the mainline.
Comment 8 Jerry James 2006-06-19 16:27:46 UTC
On behalf of the XEmacs team, I thank you for your amazingly speedy attention to this bug report.
Comment 9 Richard Biener 2006-06-23 09:52:53 UTC
Subject: Bug 28045

Author: rguenth
Date: Fri Jun 23 09:52:40 2006
New Revision: 114929

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=114929
Log:
2006-06-23  Richard Guenther  <rguenther@suse.de>

	PR middle-end/28045
	* fold-const.c (operand_equal_p): Check if the argument types
	have the same precision before stripping NOPs.

	* gcc.dg/torture/pr28045.c: New testcase.

Added:
    branches/gcc-4_1-branch/gcc/testsuite/gcc.dg/torture/pr28045.c
      - copied unchanged from r114772, trunk/gcc/testsuite/gcc.dg/torture/pr28045.c
Modified:
    branches/gcc-4_1-branch/gcc/ChangeLog
    branches/gcc-4_1-branch/gcc/fold-const.c
    branches/gcc-4_1-branch/gcc/testsuite/ChangeLog

Comment 10 Richard Biener 2006-06-23 09:57:48 UTC
Subject: Bug 28045

Author: rguenth
Date: Fri Jun 23 09:57:37 2006
New Revision: 114930

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=114930
Log:
2006-06-23  Richard Guenther  <rguenther@suse.de>

	PR middle-end/28045
	* fold-const.c (operand_equal_p): Check if the argument types
	have the same precision before stripping NOPs.

	* gcc.dg/torture/pr28045.c: New testcase.

Added:
    branches/gcc-4_0-branch/gcc/testsuite/gcc.dg/torture/pr28045.c
      - copied unchanged from r114772, trunk/gcc/testsuite/gcc.dg/torture/pr28045.c
Modified:
    branches/gcc-4_0-branch/gcc/ChangeLog
    branches/gcc-4_0-branch/gcc/fold-const.c
    branches/gcc-4_0-branch/gcc/testsuite/ChangeLog

Comment 11 Richard Biener 2006-06-23 09:57:52 UTC
Fixed.
Comment 12 patchapp@dberlin.org 2006-06-29 21:37:33 UTC
Subject: Bug number PR28045

A patch for this bug has been added to the patch tracker.
The mailing list url for the patch is http://gcc.gnu.org/ml/gcc-patches/2006-06/msg01000.html
Comment 13 Jackie Rosen 2014-02-16 13:16:58 UTC Comment hidden (spam)