This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
x86 float conditional move is buggy
- To: egcs-bugs at cygnus dot com
- Subject: x86 float conditional move is buggy
- From: hjl at lucon dot org (H.J. Lu)
- Date: Wed, 16 Dec 1998 12:53:53 -0800 (PST)
- Cc: egcs at egcs dot cygnus dot com
Hi,
Here is the original bug report on the PPro float conditional move. The
problem is x86 uses register stack for float. The operands of the float
conditional moves have to be the float registers on the register stack.
For some reason, gcc turns
(insn 170 157 45 (set (reg/v:DF 10 %st(2))
(if_then_else:DF (ne:SI (reg/v:SI 4 %esi)
(reg/v:SI 3 %ebx))
(reg/v:DF 9 %st(1))
(reg:DF 12 %st(4)))) 396 {movdfcc+2} (insn_list 33 (nil))
(nil))
where (reg/v:DF 10 %st(2)) is not on the stack at the time into
(insn:QI 178 167 47 (set (reg:DF 8 %st(0))
(if_then_else:DF (ne:SI (reg/v:SI 4 %esi)
(reg/v:SI 3 %ebx))
(reg:DF 8 %st(0))
(reg:DF 9 %st(1)))) 396 {movdfcc+2} (insn_list 33 (nil))
(nil))
It was done around line 2359 in subst_stack_regs_pat in reg-stack.c.
Before subst_stack_regs_pat, the stack looks like
stack virtual hard
top DF 9 DF 8
top-1 DF 12 DF 9
empty
the instuction tries to get
stack virtual hard
top DF 10 DF 8
top-1 DF 9 DF 9
top-2 DF 12 DF 10
empty
Instead it gets
stack virtual hard
top DF 10 st8
top-1 DF 12 st9
empty
I am not sure how it gets
(insn 170 157 45 (set (reg/v:DF 10 %st(2))
(if_then_else:DF (ne:SI (reg/v:SI 4 %esi)
(reg/v:SI 3 %ebx))
(reg/v:DF 9 %st(1))
(reg:DF 12 %st(4)))) 396 {movdfcc+2} (insn_list 33 (nil))
(nil))
where (reg/v:DF 10 %st(2)) is not on the stack. For x86, when the
destination is a float register, movxfcc is diffenerent from movxf.
movxf is a push while movxfcc is not. gcc may get confused on that.
--
H.J. Lu (hjl@gnu.org)
---
/*
Dear gcc maintainers,
I believe I have found a bug in the PentiumPro optimizer of
gcc version egcs-2.91.57 19980901 (egcs-1.1 release)
built for i686-pc-linux-gnulibc1 without any options or modifications.
The program below should multipliy a matrix with its inverse and compare
elementwise the result to the unity matrix, recording the maximum absolute
difference between the expected result and the unity matrix.
I have simplified the program as much as possible, using unity matrices as
operands. The result should be 0.
Here is the program:
*/
#include <stdio.h>
#include <math.h>
#define SIZE 10
double a [SIZE * SIZE] =
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
double ainv [SIZE * SIZE] =
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
int
main (void)
{
int i, j, k;
double diff, sum, soll, maxd;
/* compute the product a*ainv element by element and compare to
unity matrix */
maxd = 0; /* maximum of difference */
for (i = 0; i < SIZE; i++)
for (j = 0; j < SIZE; j++)
/* compute element (i,j) of product */
{
/*1*/ sum = 0;
/*2*/ soll = ((i == j) ? 1 : 0); /* this should be the result */
for (k = 0; k < SIZE; k++)
sum += a[i * SIZE + k] * ainv[k * SIZE + j];
diff = fabs (sum - soll); /* measure difference */
if (diff > maxd) /* record maximum difference */
maxd = diff;
}
printf ("maxd=%g \n", maxd);
return 0;
}
#if 0
"If I compile it with
gcc -g -O -march=i686 err.c -o err /* BUG */
I get the wrong result
maxd=NaN
The bug appears only with the combination of '-O' and '-march=i686'.
The following produce correct results:
gcc -g -O3 -march=i586 err.c -o err /* NO BUG */
gcc -g -march=i686 err.c -o err /* NO BUG */
Furthermore, the bug disappears if the lines marked /*1*/ and /*2*/
in the source are interchanged.
"
#endif