2015-09-12 30 views
1

在x86_64中,我知道mul和div opp代碼支持128個整數,方法是將較低的64位置於rax中,將較高的位置置於rdx寄存器中。我在intel內部指南中尋找某種內在因素來做到這一點,而我找不到它。我正在寫一個大字庫,其中字大小是64位。現在我正在用這樣的單詞進行劃分。用於128乘法和除法的內在函數

int ubi_div_i64(ubigint_t* a, ubi_i64_t b, ubi_i64_t* rem) 
{ 
    if(b == 0) 
     return UBI_MATH_ERR; 

    ubi_i64_t r = 0; 

    for(size_t i = a->used; i-- > 0;) 
    { 

     ubi_i64_t out; 
     __asm__("\t" 
       "div %[d] \n\t" 
       : "=a"(out), "=d"(r) 
       : "a"(a->data[i]), "d"(r), [d]"r"(b) 
       : "cc"); 
     a->data[i] = out; 


     //ubi_i128_t top = (r << 64) + a->data[i]; 
     //r = top % b; 
     //a->data[i] = top/b; 
    } 
    if(rem) 
     *rem = r; 

    return ubi_strip_leading_zeros(a); 
} 

這將是很好,如果我可以使用x86intrinsics.h標題而不是內聯asm。

+1

由於asm已經是編譯器特有的,所以你可以使用'__int128'類型,它會自動執行你想要的。 – Jester

+0

看看_mulx_u64。看起來非常適合您的使用,儘管它會生成僅存在於新型x86處理器上的mulx指令。 – ScottD

+0

鑑於體系結構特定內在函數和體系結構特定程序集之間的選擇;後者有更好的文檔記錄,更好的支持,更廣泛的理解和更容易維護(不需要猜測編譯器實際做了什麼)。 – Brendan

回答

1

gcc有__int128__uint128類型。

與它們的算術應該當它們存在時使用正確的彙編指令;過去我使用它們來獲得產品的高64位,儘管我從未用它來劃分。如果它沒有使用正確的,請根據需要提交錯誤報告/功能請求。

+0

當我在-03上構建代碼時,我對代碼進行了反編譯。我很驚訝gcc在使用128位分區時正在調用一個函數而不是內聯函數。只是看起來很慢。 – chasep255

+1

@ chasep255 GCC不使用DIV/IDIV的「擴展」形式,因爲它不合格。無論是64位x86目標上的128位紅利還是32位x86目標上的64位紅利都是如此。問題是如果標準說結果應該被截斷的話,DIV會導致分割溢出異常。例如'(unsigned long long)(((unsigned _int128)1 << 64)/ 1)'應該評估爲0,但是如果使用DIV進行評估,會導致分割溢出異常。 –

1

Last I looked into it the intrinsic were in a state of flux。在這種情況下,內部函數的主要原因似乎是由於以下事實:64位模式下的MSVC不允許內聯彙編。使用MSVC(我認爲ICC),您可以使用_umul128代替mul_mulx_u64代替mulx。這些在GCC中不起作用,至少不是GCC 4.9(_umul128比GCC 4.9更老)。我不知道GCC是否計劃支持這些,因爲您可以通過__int128(取決於您的編譯選項)間接獲得mulmulx,或直接通過行內彙編獲得。

__int128正常工作,直到您需要更大的類型和128位進位。那麼你需要adc,adcxadox,這些對於內在函數來說更是一個問題。英特爾的文檔與MSVC不同意,編譯器似乎還沒有產生adox這些內在的東西。看到這個問題:_addcarry_u64 and _addcarryx_u64 with MSVC and ICC

行內組裝可能是GCC(甚至可能是ICC)的最佳解決方案。