2011-12-09 19 views
8

我想知道在Visual C++中是否真的沒有128位劃分內部函數?在Visual C++中的128位內部劃分

有一個64x64 = 128位乘法內部函數叫做_umul128(),它很好地匹配MUL x64彙編指令。當然,我認爲將會有一個128/64 = 64位的內部分區(對DIV指令進行建模),但令人吃驚的是Visual C++和Intel C++似乎都沒有它,至少它沒有列出intrin.h。

有人可以證實嗎?我試圖在編譯器可執行文件中尋找函數名,但首先找不到_umul128,所以我想我看錯了位置。

更新:至少我現在已經在c1.dll的Visual C++ 2010中找到了模式「umul128」(沒有前導下劃線)。所有其他內部函數都列在其周圍,但不幸的是沒有「udiv128」之類的:(所以看起來他們真的已經「忘記」實現它了。

澄清:我不只是在尋找一個128位的數據類型,而是一種將128位標量int除以64位詮釋在C++中。無論哪種一固有功能天然 128位整數的支持將解決我的問題。

艾迪T:答案是否定的,沒有_udiv128在Visual Studio 2010或2012年

+1

它不是CRT的一部分。這是一個內在的,來處理器免費。但僅限於64位模式。直到你得到一個128位的處理器,沒有免費的div。鑑於pow的範圍很廣(2,128),你應該尋找任意精度庫。周圍有很多人。 –

+0

@TreeMonkie:__int18不支持VS,請參閱http://stackoverflow.com/questions/6759592/how-to-enable-int128-on-visual-studio – cxxl

+2

@Hans:對不起,我不明白。它不是一個內在的,即使在64位模式。我需要它*寫*任意精度庫:) – cxxl

回答

1

內在我不是專家,但我挖這件事:

http://research.swtch.com/2008/01/division-via-multiplication.html

有趣的東西。希望能幫助到你。

編輯:這是太精闢:http://www.gamedev.net/topic/508197-x64-div-intrinsic/

+0

這實際上很痛苦。即使你找到了所需的倒數+倒數,你仍然不得不乘以128bit的倒數,並從結果中取出最高64位,這是一個嚴重的PITA – yonil

+0

也我很難相信整個事情會不知何故勝過DIV/IDIV指令。 – yonil

10

如果你不介意的小黑客,這可能會幫助(64位模式下,未測試):

#include <windows.h> 
#include <stdio.h> 

unsigned char udiv128Data[] = 
{ 
    0x48, 0x89, 0xD0, // mov rax,rdx 
    0x48, 0x89, 0xCA, // mov rdx,rcx 
    0x49, 0xF7, 0xF0, // div r8 
    0x49, 0x89, 0x11, // mov [r9],rdx 
    0xC3    // ret 
}; 

unsigned char sdiv128Data[] = 
{ 
    0x48, 0x89, 0xD0, // mov rax,rdx 
    0x48, 0x89, 0xCA, // mov rdx,rcx 
    0x49, 0xF7, 0xF8, // idiv r8 
    0x49, 0x89, 0x11, // mov [r9],rdx 
    0xC3    // ret 
}; 

unsigned __int64 (__fastcall *udiv128)(unsigned __int64 numhi, 
             unsigned __int64 numlo, 
             unsigned __int64 den, 
             unsigned __int64* rem) = 
    (unsigned __int64 (__fastcall *)(unsigned __int64, 
            unsigned __int64, 
            unsigned __int64, 
            unsigned __int64*))udiv128Data; 

__int64 (__fastcall *sdiv128)(__int64 numhi, 
           __int64 numlo, 
           __int64 den, 
           __int64* rem) = 
    (__int64 (__fastcall *)(__int64, 
          __int64, 
          __int64, 
          __int64*))sdiv128Data; 

int main(void) 
{ 
    DWORD dummy; 
    unsigned __int64 ur; 
    __int64 sr; 
    VirtualProtect(udiv128Data, sizeof(udiv128Data), PAGE_EXECUTE_READWRITE, &dummy); 
    VirtualProtect(sdiv128Data, sizeof(sdiv128Data), PAGE_EXECUTE_READWRITE, &dummy); 
    printf("0x0000ABCDEF000000000000/0x0001000000000000 = 0x%llX\n", 
     udiv128(0x0000AB, 0xCDEF000000000000, 0x0001000000000000, &ur)); 
    printf("-6/-2 = %lld\n", 
     sdiv128(-1, -6, -2, &sr)); 
    return 0; 
} 
+1

對於MSVC,編譯期間可以使用#pragma部分將這些函數編碼到代碼段 –

+0

@Maratyszcza:你說得對。 –

+0

爲什麼不能使用內聯彙編? –

2

小的提升 - 少一條指令

extern "C" digit64 udiv128(digit64 low, digit64 hi, digit64 divisor, digit64 *remainder); 

; Arguments 
; RCX  Low Digit 
; RDX  High Digit 
; R8  Divisor 
; R9  *Remainder 

; RAX  Quotient upon return 

.code 
udiv128 proc 
    mov rax, rcx ; Put the low digit in place (hi is already there) 
    div r8  ; 128 bit divide rdx-rax/r8 = rdx remainder, rax quotient 
    mov [r9], rdx ; Save the reminder 
    ret  ; Return the quotient 
udiv128 endp 
end