[GHC] #4368: T4144(dyn) failing on x86/Linux
GHC
cvs-ghc at haskell.org
Wed Oct 6 08:22:54 EDT 2010
#4368: T4144(dyn) failing on x86/Linux
-------------------------------+--------------------------------------------
Reporter: simonmar | Owner: benl
Type: bug | Status: new
Priority: highest | Milestone: 7.0.1
Component: Compiler (NCG) | Version: 6.13
Keywords: | Testcase:
Blockedby: | Difficulty:
Os: Linux | Blocking:
Architecture: x86 | Failure: Runtime crash
-------------------------------+--------------------------------------------
Changes (by simonmar):
* owner: simonmar => benl
* component: Compiler => Compiler (NCG)
Comment:
This is a bug in the `-fregs-graph` register allocator, which is now on by
default with `-O2`.
This cmm is from the code generated for
`libraries/base/GHC/IO/Handle/Text.hs` when compiled with `-dynamic`:
{{{
==================== Optimised Cmm ====================
s4xo_ret()
{ [const GHC.IO.Handle.Text.$wa1_srt-s4xo_info+28;, const
8388627;,
const 65568;]
}
c6mw:
if (I32[R1 + 3] != 0) goto c6my;
R1 = PicBaseReg + lvl5_r3Dc_closure at gotoff + 1;
Sp = Sp + 80;
jump (I32[Sp + 0]) ();
c6my:
I32[I32[Sp + 64] + 4] = I32[Sp + 72];
_c6mu::I32 = BaseReg;
_c6mt::I32 = I32[Sp + 64];
foreign "ccall"
I32[PicBaseReg + dirty_MUT_VAR at got]((_c6mu::I32, PtrHint),
(_c6mt::I32,
PtrHint))[_unsafe_call_];
R1 = I32[Sp + 68];
I32[Sp + 0] = PicBaseReg + s4xq_info at gotoff;
if (R1 & 3 != 0) goto c6mB;
jump I32[R1] ();
c6mB: jump s4xq_info ();
}
}}}
The native code is correct:
{{{
==================== Native code ====================
.text
.align 4,0x90
.long base_GHCziIOziHandleziText_zdwa1_srt-(s4xo_info)+28
.long 8388627
.long 65568
s4xo_info:
.Lc6mw:
call 1f
1: popl %vI_n6mL
addl $_GLOBAL_OFFSET_TABLE_+(.-1b), %vI_n6mL
cmpl $0,3(%esi)
jne .Lc6my
movl %vI_n6mL,%vI_n6mM
addl $r3Dc_closure at gotoff,%vI_n6mM
leal 1(%vI_n6mM),%esi
addl $80,%ebp
jmp *0(%ebp)
.Lc6my:
movl 72(%ebp),%vI_n6mN
movl 64(%ebp),%vI_n6mO
movl %vI_n6mN,4(%vI_n6mO)
movl %ebx,%vI_c6mu
movl 64(%ebp),%vI_c6mt
pushl %vI_c6mt
pushl %vI_c6mu
movl dirty_MUT_VAR at got(%vI_n6mL),%vI_n6mP
call *%vI_n6mP
addl $8,%esp
movl 68(%ebp),%esi
movl %vI_n6mL,%vI_n6mQ
addl $s4xq_info at gotoff,%vI_n6mQ
movl %vI_n6mQ,0(%ebp)
testl $3,%esi
jne .Lc6mB
jmp *(%esi)
.Lc6mB:
jmp s4xq_info
}}}
The liveness analysis is correct:
{{{
==================== Liveness annotations added ====================
s4xo_ret()
{ const GHC.IO.Handle.Text.$wa1_srt-s4xo_info+28;
const 8388627;
const 65568;
# firstId = Just c6mw
# liveOnEntry = Just [(c6mw, []), (c6my, [(n6mL, %vI_n6mL)]),
(c6mB, [])]
}
[NONREC
c6mw:
call 1f
1: popl %vI_n6mL
addl $_GLOBAL_OFFSET_TABLE_+(.-1b), %vI_n6mL
# born: %vI_n6mL
cmpl $0,3(%esi)
jne .Lc6my
movl %vI_n6mL,%vI_n6mM
# born: %vI_n6mM
# r_dying: %vI_n6mL
addl $r3Dc_closure at gotoff,%vI_n6mM
leal 1(%vI_n6mM),%esi
# r_dying: %vI_n6mM
addl $80,%ebp
jmp *0(%ebp)
,
NONREC
c6my:
movl 72(%ebp),%vI_n6mN
# born: %vI_n6mN
movl 64(%ebp),%vI_n6mO
# born: %vI_n6mO
movl %vI_n6mN,4(%vI_n6mO)
# r_dying: %vI_n6mN %vI_n6mO
movl %ebx,%vI_c6mu
# born: %vI_c6mu
movl 64(%ebp),%vI_c6mt
# born: %vI_c6mt
pushl %vI_c6mt
# r_dying: %vI_c6mt
pushl %vI_c6mu
# r_dying: %vI_c6mu
movl dirty_MUT_VAR at got(%vI_n6mL),%vI_n6mP
# born: %vI_n6mP
call *%vI_n6mP
# born: %r0 %r2 %r3 %r16 %r17 %r18 %r19 %r20 %r21
%r24 %r25 %r26 %r27 %r28 %r29 %r30 %r31
# r_dying: %vI_n6mP
# w_dying: %r0 %r2 %r3 %r16 %r17 %r18 %r19 %r20 %r21
%r24 %r25 %r26 %r27 %r28 %r29 %r30 %r31
addl $8,%esp
movl 68(%ebp),%esi
movl %vI_n6mL,%vI_n6mQ
# born: %vI_n6mQ
# r_dying: %vI_n6mL
addl $s4xq_info at gotoff,%vI_n6mQ
movl %vI_n6mQ,0(%ebp)
# r_dying: %vI_n6mQ
testl $3,%esi
jne .Lc6mB
jmp *(%esi)
,
NONREC
c6mB:
jmp s4xq_info
]
}
}}}
But the final register-allocated code is wrong:
{{{
==================== Registers allocated ====================
.text
.align 4,0x90
.long base_GHCziIOziHandleziText_zdwa1_srt-(s4xo_info)+28
.long 8388627
.long 65568
s4xo_info:
.Lc6mw:
call 1f
1: popl %eax
addl $_GLOBAL_OFFSET_TABLE_+(.-1b), %eax
cmpl $0,3(%esi)
jne .Lc6my
addl $r3Dc_closure at gotoff,%eax
movl %eax,64(%esp) # ** spill $eax here
leal 1(%eax),%esi
addl $80,%ebp
jmp *0(%ebp)
.Lc6my:
movl 72(%ebp),%eax # ** we just clobbered $eax!!
movl 64(%ebp),%ecx
movl %eax,4(%ecx)
movl %ebx,%ecx
movl 64(%ebp),%eax
pushl %eax
pushl %ecx
movl 72(%esp),%eax # ** failed attempt to reload $eax (it wasn't
spilled)
movl dirty_MUT_VAR at got(%eax),%eax
call *%eax
addl $8,%esp
movl 68(%ebp),%esi
movl 64(%esp),%eax
addl $s4xq_info at gotoff,%eax
movl %eax,64(%esp)
movl %eax,0(%ebp)
testl $3,%esi
jne .Lc6mB
jmp *(%esi)
.Lc6mB:
jmp s4xq_info
}}}
Note the lines with comments. It's as if the register allocator got the
dependency graph wrong, because `$eax` is spilled in a basic block that
does not occur before the one in which it is reloaded.
Ben, can you shed any light?
--
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4368#comment:2>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the Glasgow-haskell-bugs
mailing list