2011-12-09 5 views
8

Visual C++에서 128 비트 본질 내장 함수가 실제로 있는지 궁금합니다.Visual C++ 128 비트 본질 내장

MUL x64 어셈블러 명령어와 잘 일치하는 _umul128()이라는 64x64 = 128 비트 곱셈 내장 함수가 있습니다.

본질적으로 128/64 = 64 비트 나눗셈 내장 함수 (DIV 명령어 모델링)가 있다고 가정했지만 비주얼 C++이나 인텔 C++에는없는 것으로 보입니다. 적어도 나열되어 있지는 않습니다. intrin.h.

누군가가이를 확인할 수 있습니까? 나는 컴파일러 실행 파일의 함수 이름에 대해 grep'ing을 시도했지만 처음에는 _umul128을 찾을 수 없었으므로 잘못된 지점을 찾았습니다.

업데이트 : 적어도 Visual C++ 2010의 c1.dll에서 "umul128"이라는 패턴을 발견했습니다. 다른 모든 intrinsics는 그 주위에 나열되지만 불행히도 "udiv128"또는 이와 비슷한 것은 아닙니다 :(그래서 그들은 실제로 그것을 구현하는 것을 "잊어 버린"것처럼 보입니다.

분명히하기 위해서 : 저는 128 비트 데이터 타입을 찾고있을뿐만 아니라, 128 비트 스칼라 int를 64 비트로 나눌 수있는 방법을 찾고 있습니다. 어느 쪽 내장 함수 또는 기본 128 비트 정수 지원이 내 문제를 해결할 것입니다. ++ C에서 int로.

에디를 t : 대답은 '아니오', 거기에 내가 전문가는 오전없는 비주얼 스튜디오 2010 또는 2012

+1

CRT의 일부가 아닙니다. 그것은 내재적이며, 프로세서는 무료입니다. 그러나 64 비트 모드에서만 가능합니다. 당신이 128 조금 가공업자를 얻을 때까지 div를위한 공짜 물건 없음. 엄청나게 방대한 양의 pow (2, 128)를 감안할 때 임의 정밀도 라이브러리를 찾아야합니다. 주변에 많은 사람들이 있어요. –

+0

@TreeMonkie : VS에서 __int18을 지원하지 않습니다. http://stackoverflow.com/questions/6759592/how-to-enable-int128-on-visual-studio – cxxl

+2

@Hans : 죄송합니다, 이해가 안됩니다. 64 비트 모드가 아니라 내장 함수가 아닙니다. 그리고 임의의 정밀도 라이브러리를 쓰려면 * 필요합니다. – cxxl

답변

1

에서 고유 더 _udiv128이 없지만, 나는이 발굴 :

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

재미있는 물건. 희망이 도움이됩니다.

편집 : 이것은 통찰력이 너무 : http://www.gamedev.net/topic/508197-x64-div-intrinsic/

+0

실제로는 꽤 고통 스럽습니다.상호 적 + 시프트가 필요하다고 판단 되더라도 128 비트 nom에 역수를 곱하고 그 결과에서 상위 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 section을 사용하여 코드 세그먼트에 이러한 함수를 넣을 수 있습니다. –

+0

@Maratyszcza : 네 말이 맞아. –

+0

인라인 어셈블리를 사용할 수없는 이유는 무엇입니까? –

2

작은 개선 - 1 less instruction

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