On a i686 platform, the example below is miscompiled with -O1. I expect this program to print -0.96. Here's what it actually does: $ g++ -O1 -o y y.cc $ ./y -1.288766 $ g++ -o y y.cc $ ./y -0.960000 $ The value that the optimized version prints is actually different on each run of the program. Here's the generated code for main(), .globl main .type main, @function main: pushl %ebp movl %esp, %ebp subl $24, %esp movl %ebx, -8(%ebp) movl %esi, -4(%ebp) andl $-16, %esp subl $16, %esp movl $0, 12(%esp) movl 8(%esp), %ebx ; this seems to load ebx with garbage??? movl 12(%esp), %esi fldz fstl 8(%esp) fstpl (%esp) call _Z8x_from_zdd fstpl 4(%esp) movl %ebx, 8(%esp) ; this clobbers half of the arg with ; the garbage movl %esi, 12(%esp) movl $0, (%esp) call _Z17local_to_trflocalidi movl $0, %eax movl -8(%ebp), %ebx movl -4(%ebp), %esi movl %ebp, %esp popl %ebp ret It looks to me like the error occurs during RTL generation. Here's the tree dump from the t87.final_cleanup file (slightly trimmed): void local_to_trflocal(int, double, int) (D.1741, x_loc, D.1743) { <bb 0>: printf (&"%f\n"[0], x_loc); return; } double x_from_z(double, double) (pitch, stereo) { <bb 0>: return -9.59999999999999964472863211994990706443786621094e-1 / cos (stereo); } int main() () { <bb 0>: local_to_trflocal (0, x_from_z (0.0, 0.0), 0); return 0; } But in the 00.expand file, here's the sequence leading to the local_to_trflocal() call: (insn 27 26 28 1 (set (mem/i:DF (plus:SI (reg/f:SI 56 virtual-outgoing-args) (const_int 4 [0x4])) [0 S8 A32]) (reg:DF 71)) -1 (nil) (nil)) (insn 28 27 29 1 (set (mem:DI (plus:SI (reg/f:SI 56 virtual-outgoing-args) (const_int 8 [0x8])) [0 S8 A8]) (reg:DI 68)) -1 (nil) (nil)) (insn 29 28 30 1 (set (mem:SI (reg/f:SI 56 virtual-outgoing-args) [0 S4 A32]) (const_int 0 [0x0])) -1 (nil) (nil)) (call_insn 30 29 31 1 (call (mem:QI (symbol_ref:SI ("_Z17local_to_trflocalidi") [flags 0x3] <function_decl 0xb7f0df80 local_to_trflocal>) [0 S1 A8]) (const_int 16 [0x10])) -1 (nil) (nil) (nil)) Reg 71 here is the return value from x_from_z. I don't know where the DI store to v-o-a+8 is coming from... Environment: System: Linux karma 2.6.12.1sss #2 Thu Jul 7 00:28:21 EDT 2005 i686 i686 i386 GNU/Linux Architecture: i686 <machine, os, target, libraries (multiple lines)> host: i686-pc-linux-gnu build: i686-pc-linux-gnu target: i686-pc-linux-gnu configured with: /home/sss/gcc/gcc/configure --prefix=/usr/local/gcc --enable-threads=posix --enable-long-long --enable-languages=c,c++,f95 How-To-Repeat: Compile with -O1 ----------------------------------------------------- //g++ -O1 -g -o y y.cc extern "C" double cos(double); extern "C" int printf (...); double x_from_z(double pitch=0, double stereo=0) { return -0.96/cos(stereo); } void local_to_trflocal(int, double x_loc, int=0) { printf ("%f\n", x_loc); } int main() { local_to_trflocal(0, x_from_z()); return 0; } -----------------------------------------------------
Fix: <how to correct or work around the problem, if known (multiple lines)>
Confirmed.
Reduced testcase: extern "C" double cos(double); extern "C" void abort(void); double x_from_z(double pitch=0, double stereo=0); // __attribute__((const)); double x_from_z(double pitch, double stereo) { return 1.0/cos(stereo); } void local_to_trflocal(int, double x_loc, int=0) { if (x_loc != 1.0) abort (); } int main() { local_to_trflocal(0, x_from_z()); return 0; } Code is ok if you declare x_from_z const.
And here is a C testcase: double cos(double); void abort(void); double x_from_z(double pitch, double stereo); // __attribute__((const)); double x_from_z(double pitch, double stereo) { return 1.0/cos(stereo); } void local_to_trflocal(int b, double x_loc, int a) { if (x_loc != 1.0) abort (); } int main() { local_to_trflocal(0, x_from_z(0,0),0); return 0; }
The difference between 4.0 and HEAD is the expr.c hunk of http://gcc.gnu.org/ml/gcc-patches/2005-07/msg02021.html If Paolo's reversion of that: http://gcc.gnu.org/ml/gcc-patches/2005-09/msg00589.html makes it in, the testcase will pass again. The real problem is I think that when calls.c decides to save stack area under an argument for the inner expand_call, but that argument partially overlaps with the result of the call, we save/restore the argument with the inner expand_call's argument mode and don't just limit to the actual bytes that have already been initialized. So we read some uninitialized bits from the stack and overwrite with them the computed argument.
Any news on getting this fixed?
both testcases works for me 4.1.0-20051005. i have applied patches for: PR7776, PR20297, PR22533, PR23948, PR19505, PR20606/PR24069.
Yup, this is a showstoppper.
Jakub, ping! What's up with this one?
For the record, Jakub has apparently dropped this bug from his list to put this bug back into unassigned state.
And for the realy record this was fixed by the patch which fixed PR 24003 also.