Bug 70541 - GCC Math error with negate, or and a subtract
GCC Math error with negate, or and a subtract
Status: CLOSED RAWHIDE
Product: Red Hat Linux
Classification: Retired
Component: gcc (Show other bugs)
7.2
i686 Linux
medium Severity medium
: ---
: ---
Assigned To: Jakub Jelinek
Brian Brock
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2002-08-02 08:56 EDT by wsnyder
Modified: 2007-04-18 12:45 EDT (History)
1 user (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2002-08-04 11:06:54 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:


Attachments (Terms of Use)

  None (edit)
Description wsnyder 2002-08-02 08:56:55 EDT
From Bugzilla Helper:
User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461)

Description of problem:
The snippet below returns the wrong value with gcc at
all optimization levels on linux.  It works OK with
other compilers and on gcc *solaris* 2.95.2.


Version-Release number of selected component (if applicable):


How reproducible:
Always

Steps to Reproduce:
// The code below will print BUG EXISTS on linux gcc only, not solaris or
// non-gcc.  Note that in the third print, I manually substituted the
// result that GCC says is in a midterm into the equation, and I get the
// right result!

// $ uname -a
// Linux  2.4.7-10smp #1 SMP Thu Sep 6 17:09:31 EDT 2001 i686 unknown
// $ gcc --version
// 2.96
// $ cat /etc/redhat-release 
// Red Hat Linux release 7.2 (Enigma)
// $ gcc {SNIPPETBELOW.cpp}
// $ a.out
//	ff9d6df9 exp fb76ebf7
//	***BUG EXISTS****
//	fb36c396 exp fb36c396
//	fb76ebf7 exp fb76ebf7

#ifdef __SOLARIS
#include <sys/types.h>
#else
#include <stdint.h>	// uint32_t
#endif
#include <stdio.h>

#define VL_WORDSIZE 32			// Bits in a word
#define VL_SIZEBITS (VL_WORDSIZE-1)	// Bit mask for bits in a word
#define VL_WORDS(nbits) (((nbits)+(VL_WORDSIZE-1))/VL_WORDSIZE)	// Words this # 
bits needs (1 bit=1 word)
#define VL_BITWORD(bit)	((bit)/VL_WORDSIZE)
#define VL_BITBIT(bit)	((bit)&VL_SIZEBITS)

static inline uint32_t VL_RANGE_IWII(uint32_t* lwp, uint32_t msb, uint32_t lsb) 
{
    int nbitsonright = 32-lsb;  // bits that come from low word
    return ((lwp[VL_BITWORD(msb)]<<nbitsonright)
	    |(lwp[VL_BITWORD(lsb)]>>VL_BITBIT(lsb)));
}


void main() {
    uint32_t W1065[2] = {0xffffffffU, 0x1FFFFFU};
    uint32_t W1066;

    W1066 = 0x4c93c6a;

    uint32_t bugvalue = 
	   ((0x1a0469e1U | 
	     (0xf2626901U - 
	      VL_RANGE_IWII(W1065, 0x34, 0x15)))
	    | (-(W1066)));

    printf("%x exp fb76ebf7\n", bugvalue);
    if (bugvalue != 0xfb76ebf7U) { printf ("***BUG EXISTS****\n"); }

    printf("%x exp fb36c396\n",
	   (-(W1066)));
    printf("%x exp fb76ebf7\n",
	   ((0x1a0469e1U | 
	     (0xf2626901U - 
	      VL_RANGE_IWII(W1065, 0x34, 0x15)))
	    | 0xfb36c396U));
}


Actual Results:  	ff9d6df9 exp fb76ebf7
	***BUG EXISTS****


Expected Results:  	fb76ebf7 exp fb76ebf7


Additional info:

This was uncovered by a automatic compiler checker which is testing a program 
that generates C code.  It took about 5 hours of continuous compiles to get 
this, so it's got to be something relatively obscure.
Comment 1 Olivier Baudron 2002-08-03 05:58:07 EDT
Same here, on my rawhide box (gcc-3.2-0.1).
Comment 2 Olivier Baudron 2002-08-03 07:05:08 EDT
Here is the shortest buggy testcase I could extract:

/* --------------- cut here ---------------

#include <stdint.h>
#include <stdio.h>

uint32_t f() { return 1u; }

int main() {
    uint32_t n = 1u;
    uint32_t bugvalue, goodvalue;

    bugvalue  = (0x1u | (0x2u - f())) | (-n);
    goodvalue = (0x1u | (0x2u - 1u))  | (-n);

    printf("bugvalue = %x\ngoodvalue = %x\n", bugvalue, goodvalue);

    return 0;
}

/* --------------- cut here --------------- */

$ gcc -Wall -o test test.c           
$ ./test 
bugvalue = 1
goodvalue = ffffffff
Comment 3 Olivier Baudron 2002-08-04 11:06:49 EDT
A little shorter. Outputs 1 instead of -1.

#include <stdio.h>
int main() {
    int n=1, m;
    m = (1 | (2 - n)) | (-n);
    printf("m=%d\n", m);
    return 0;
}
Comment 4 Jakub Jelinek 2002-08-13 15:06:33 EDT
Should be fixed in gcc-3.2-0.3 (and on gcc CVS trunk).

Note You need to log in before you can comment on or make changes to this bug.