mit-scheme-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[MIT-Scheme-devel] Re: Bug in x86-64 compiler?


From: Taylor R Campbell
Subject: [MIT-Scheme-devel] Re: Bug in x86-64 compiler?
Date: Sat, 24 Apr 2010 16:01:50 -0400
User-agent: IMAIL/1.21; Edwin/3.116; MIT-Scheme/7.7.90.+

   Date: Sat, 24 Apr 2010 12:17:15 -0700
   From: Chris Hanson <address@hidden>

   There's a reproducible bug in Edwin that appears to be a compiler bug
   in the x86-64 back end.  The problem is the following sequence (from
   edwin/bufwmc, procedure column->y, the second to last procedure in the
   file):

           ;; (assign (register #x3a) (fixnum-2-args fixnum-quotient (register
   #x29) (register #x2b) #f))
           (mov q (r 0) (r 1))
           (cse q (r 2) (r 0))
           (idiv q ((r 2) : (r 0)) (@ro 6 #x300))
           (sal q (r 0) (&u 6))

Here's the analogous i386 code:

        ;; (assign (register #x2a) (fixnum-2-args fixnum-quotient (register 
#x19) (register #x1b) #f))
        (mov w (r 0) (r 1))
        (mov w (r 2) (r 0))
        (sar w (r 2) (& #x1f))
        (idiv w (r 0) (@ro w 6 #x600))
        (sal w (r 0) (& 6))

So I don't think this is specific to the x86-64 back end.  (The LAP
generation methods for FIXNUM-QUOTIENT are nearly identical, except
for MOV/SAR vs CSE, which has to do with some fiddly details of sign
extension that I have thoroughly forgotten.)  What's a little puzzling
is that any pseudo-registers should be saved into their homes in the
x86-64 code -- there ought to be plenty machine registers to go
around.  I guess this just reflects the greediness of the register
allocation algorithm, which doesn't look ahead to see what machine
registers the following instructions may need.

   Basically, just before this code is run, r0 contains register #x2b
   (x-max), and r1 contains register #x29 (column).  The first
   instruction clobbers r0, losing x-max, then the idiv instruction
   refers to register #x2b's memory home; however that value was never
   saved to memory, so whatever is there is complete junk.  Usually the
   result of the idiv instruction is an exception that crashes Scheme.
   Sometimes it's just the wrong answer.

Just before lie the instructions

        (mov w (@ro w 6 #x600) (r 0))   ; i386
        ...
        (mov w (r 3) (@ro w 6 #x600))
        ...
        (mov w (r 0) (r 3))

        (mov q (@ro 6 #x300) (r 0))     ; x86-64
        ...
        (mov q (r 3) (@ro 6 #x300))
        ...
        (mov q (r 0) (r 3))

with no writes to r3 in the ellipsis.  These instructions are skipped,
though, if LINE-END? is false.  What I think happened is that, upon
seeing

(if line-end?
    (if (eq? (fix:remainder column x-max) 0)
        ...
        (fix:quotient column x-max))
    (fix:quotient column x-max)),

the RTL optimizer merged the common suffixes for the tail expression

(fix:quotient column x-max),

and the register allocator saved X-MAX (formerly in r0) into its home
#x300/#x600, for the evaluation of

(eq? (fix:remainder column x-max) 0),

but failed to reflect the save along both paths into the common suffix
block.  Consequently, the common suffix block thinks that X-MAX will
be in its home, but the path when LINE-END? is false fails to save
X-MAX into its home.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]