Tony
Tony

Reputation: 9

When using emacs lisp, if the value exceed most-negative-number

So, if I multiply two values: emacs -batch -eval '(print (* 1252463 -4400000000000))' It will exceed most-negative-fixnum frame and will return mathematically wrong answer. What will be the difference in instruction level between -O2 flag, -O2 -fsanitize=undefined flag, and -O2 -fwrapv flag?

Upvotes: 0

Views: 270

Answers (1)

Brian Malehorn
Brian Malehorn

Reputation: 2685

In emacs? Probably nothing. The function that is compiled probably looks like this:

int multiply(int x, int y) {
    return x * y;
}

If we compile that and look at the assembly (gcc -S multiply.c && cat multiply.s), we get

multiply:
    pushq   %rbp
    movq    %rsp, %rbp
    movl    %edi, -4(%rbp)
    movl    %esi, -8(%rbp)
    movl    -4(%rbp), %eax
    imull   -8(%rbp), %eax
    popq    %rbp
    ret

See the imull instruction? It's doing a regular multiply. What if we try gcc -O2 -S multiply.c?

multiply:
    movl    %edi, %eax
    imull   %esi, %eax
    ret

Well that's certainly removed some code, but it's still doing imull, a regular multiplication.

Let's try to get it to not use imull:

int multiply(int x) {
    return x * 2;
}

With gcc -O2 -S multiply.c, we get

multiply:
    leal    (%rdi,%rdi), %eax
    ret

Instead of computing the slower x * 2, it instead computed x + x, because addition is faster than multiplication.

Can we get -fwrapv to do produce different code? Yes:

int multiply(int x) {
    return x * 2 < 0;
}

With gcc -O2 -S multiply.c, we get

multiply:
    movl    %edi, %eax
    shrl    $31, %eax
    ret

So it was simplified into x >> 31, which is the same thing as x < 0. In math, if x * 2 < 0 then x < 0. But in the reality of processors, if x * 2 overflows it may become negative, for example 2,000,000,000 * 2 = -294967296.

If you force gcc to take this into account with gcc -O2 -fwrapv -S temp.c, we get

multiply:
    leal    (%rdi,%rdi), %eax
    shrl    $31, %eax
    ret

So it optimized x * 2 < 0 to x + x < 0. It might seem strange to have -fwrapv not be the default, but C was created before it was standard for multiplication to overflow in this predictable manner.

Upvotes: 2

Related Questions