------- Comment #6 from bonzini at gnu dot org 2006-05-26 07:46 ------- There are indeed differences in the generated code.
aj_f_times2 is equal without and with the patch. aj_d_times2 has this (left = old, right = patched): movsd %xmm0, -40(%rbp) | movsd %xmm0, -32(%rbp) movq -40(%rbp), %rax | movsd %xmm1, -24(%rbp) movsd %xmm1, -40(%rbp) < movq -40(%rbp), %rdx < movq %rax, -32(%rbp) < movq %rdx, -24(%rbp) < This is just better code. The miscompiled function is aj_ld_times2, which is like this (some code moved for clarity): fldt 16(%rbp) fldt 16(%rbp) fadd %st(0), %st fadd %st(0), %st fstpt -48(%rbp) fstpt -48(%rbp) So far so good. movq -32(%rbp), %rax movq -32(%rbp), %rax movl -24(%rbp), %edx movl -24(%rbp), %edx movq %rax, -32(%rbp) movq %rax, -32(%rbp) movl %edx, -24(%rbp) movl %edx, -24(%rbp) Useless, and also accessing uninitialized memory, but this is -O0. fldt 32(%rbp) fldt 32(%rbp) fadd %st(0), %st fadd %st(0), %st fstpt -32(%rbp) fstpt -32(%rbp) Also good. movq -48(%rbp), %rax movq -48(%rbp), %rax movl -40(%rbp), %edx movl -40(%rbp), %edx movq %rax, -48(%rbp) movq %rax, -48(%rbp) movl %edx, -40(%rbp) movl %edx, -40(%rbp) Useless. movq -48(%rbp), %rax movq -48(%rbp), %rax movl -40(%rbp), %edx movl -40(%rbp), %edx movq -32(%rbp), %rcx movq -32(%rbp), %rcx movl -24(%rbp), %ebx movl -24(%rbp), %ebx These are -O0 stupidities. flds .LC0(%rip) < fstp %st(0) < fstp %st(1) < I don't have a clue what this is for. What is .LC0? The only thing I'm sure about, is that this causes a stack underflow... movq %rax, -64(%rbp) movq %rax, -64(%rbp) movl %edx, -56(%rbp) movl %edx, -56(%rbp) fldt -64(%rbp) fldt -64(%rbp) movq %rcx, -64(%rbp) movq %rcx, -64(%rbp) movl %ebx, -56(%rbp) movl %ebx, -56(%rbp) fldt -64(%rbp) fldt -64(%rbp) > flds .LC0(%rip) > fstp %st(0) > fstp %st(1) ... the bug is that it is moved afterwards, after the result was loaded on the stack, and the underflowing fstp clobbers the return value. The wrong instruction is produced by a (clobber (reg/i:XC 8 st)). The patched GCC moves the clobber later. The RTL produced by the patched GCC is sane until flow2, and the messed up by the stack register conversion pass: (insn 41 57 58 3 (set (reg:XF 10 st(2) [orig:66 <result> ] [66]) (mem/c:XF (plus:DI (reg/f:DI 6 bp) (const_int -64 [0xffffffffffffffc0])) [0 S16 A8])) 99 {*movxf_integer} (nil) (nil)) ... (insn 43 59 25 3 (set (reg:XF 11 st(3) [orig:67 <result>+16 ] [67]) (mem/c:XF (plus:DI (reg/f:DI 6 bp) (const_int -64 [0xffffffffffffffc0])) [0 S16 A8])) 99 {*movxf_integer} (nil) (nil)) (note 25 43 28 3 NOTE_INSN_FUNCTION_END) (insn 28 25 29 3 (clobber (reg/i:XC 8 st)) -1 (nil) (nil)) (insn 29 28 30 3 (set (reg:XF 8 st [ <result> ]) (reg:XF 10 st(2) [orig:66 <result> ] [66])) 99 {*movxf_integer} (nil) (nil)) (insn 30 29 35 3 (set (reg:XF 9 st(1) [+16 ]) (reg:XF 11 st(3) [orig:67 <result>+16 ] [67])) 99 {*movxf_integer} (nil) (nil)) (insn 35 30 64 3 (use (reg/i:XC 8 st)) -1 (nil) (nil)) Latent bug in stack, CCing sayle. -- bonzini at gnu dot org changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |sayle at gcc dot gnu dot org http://gcc.gnu.org/bugzilla/show_bug.cgi?id=27390