2015-10-27 28 views
0

因此,如果我乘以兩個值: emacs -batch -eval'(print(* 1252463 -4400000000000))' 它會超過大多數負數 - fixnum框架並將返回數學錯誤的答案。 -O2標誌,-O2 -fsanitize =未定義標誌和-O2 -fwrapv標誌之間的指令級別差異是什麼?當使用emacs lisp時,如果數值超過最大負數

回答

2

在emacs中?可能沒什麼。這可能是編譯的功能如下:

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

如果我們編譯,並期待在組件(gcc -S multiply.c && cat multiply.s),我們得到

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 

imull指令?它正在進行有規律的繁殖。如果我們嘗試gcc -O2 -S multiply.c怎麼辦?

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

嗯,這的確刪除了一些代碼,但它仍然在做imull,一個普通乘法。

讓我們試着去得到它不使用imull

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

隨着gcc -O2 -S multiply.c,我們得到

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

而是計算較慢x * 2的,它不是計算x + x,因爲除了比速度更快乘法。

我們可以得到-fwrapv來產生不同的代碼嗎?是:

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

隨着gcc -O2 -S multiply.c,我們得到

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

所以簡化爲x >> 31,這是同樣的事情x < 0。在數學中,如果x * 2 < 0然後x < 0。但在處理器的實際情況中,如果x * 2溢出,則可能會變爲負值,例如2,000,000,000 * 2 = -294967296

如果強制GCC考慮到這與gcc -O2 -fwrapv -S temp.c,我們得到

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

因此,優化x * 2 < 0x + x < 0。將-fwrapv設置爲默認值可能看起來很奇怪,但是C是在這種可預測的方式溢出標準之前創建的。

+0

如果使用-fsanitize = undefined標誌,你知道會發生什麼嗎?因爲它拋出了未定義的外部函數__ubsan_handle_overflow,並且不會執行。 – Tony

+0

聽起來像你安裝了clang錯誤,'-fsanitize = undefined'對我來說工作正常。嘗試重新安裝? 它應該輸出一個錯誤消息,如'multiply.c:3:14:運行時錯誤:有符號整數溢出:2000000000 * 2不能用'int'類型表示。我非常懷疑,如果使用'-fsanitize = undefined'編譯emacs,它會正常運行,人們總是依賴未定義的行爲。 –

相關問題