On 23/03/2012 00:59, Logan Bell wrote:
Nick,

I went ahead and created a JIRA story with the original e-mail of this
thread:
https://issues.apache.org/jira/browse/LUCY-216

On this ticket you should see 4 attachments:

Inversion.sO0   19kb (Without optimization)
Inversion.sO0   4kb (Ignore, this was a mistake unable to figure out how to
delete from Jira)
Inversion.sO1   16kb (With optimization)

Thanks, Logan. This is definitely a compiler bug. Here's the relevant part of the assembler output for the inner loop of Inversion_invert (comments are mine):

LBB12_4:
        movq    (%rbx), %rax        # cur_token = *tokens;
        movl    %r9d, 48(%rax)      # cur_token->pos = token_pos;
        movl    44(%rax), %eax      # %eax = cur_token->pos_inc
        testl   %eax, %eax
        leal    (%rax,%r9), %r15d   # %r15d = %eax + token_pos
        jns     LBB12_6
        [ code for THROW(...) ]
LBB12_6:
        addq    $8, %rbx
        cmpq    %r14, %rbx
        movl    %r15d, %r9d
        jb      LBB12_4

The "if" statement in the loop is compiled to the following instructions:

        testl   %eax, %eax
        jns     LBB12_6

Where %eax contains cur_token->pos_inc. So the "if" statement basically becomes:

        if (cur_token->pos_inc < 0)

Which is of course bogus. It really makes me wonder why the compiler gets this very simple loop wrong. My best guess is that clang tries to optimize the standard way to test for integer overflow in C and somehow gets it wrong. Since overflows rarely happen, this could explain why this bug wasn't noticed early on.

Nick

Reply via email to