Visual C ++中的128位内部分割

时间:2011-12-09 23:50:47

标签: visual-c++ intrinsics integer-division 128-bit

我想知道在Visual C ++中是否真的没有128位除法内部函数?

有一个名为_umul128()的64x64 = 128位乘法内部函数,它很好地匹配MUL x64汇编程序指令。

当然,我假设会有一个128/64 = 64位内部分区(对DIV指令进行建模),但令我惊讶的是,Visual C ++和英特尔C ++似乎都没有它,至少它是未在intrin.h中列出。

有人可以证实吗?我尝试grep'ing编译器可执行文件中的函数名称,但首先找不到_umul128,所以我想我看错了。

更新:至少我现在在Visual C ++ 2010的c1.dll中找到了模式umul128(没有前导下划线)。所有其他内在函数都列在它周围,但遗憾的是没有“udiv128”或者喜欢:(所以看起来他们真的已经“忘记”去实现它了。

澄清一下:我不只是在寻找128位数据类型,而是在C ++中将128位标量int除以64位int的方法。 内部函数本机 128位整数支持可以解决我的问题。

编辑:答案是否定的,截至2017年,Visual Studio 2010中没有_udiv128内在函数,但它在Visual Studio 2019 RTM中可用

4 个答案:

答案 0 :(得分: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("0x00000123456789ABCDEF000000000000 / 0x0001000000000000 = 0x%llX\n",
         udiv128(0x00000123456789AB, 0xCDEF000000000000, 0x0001000000000000, &ur));
  printf("-6 / -2 = %lld\n",
         sdiv128(-1, -6, -2, &sr));
  return 0;
}

答案 1 :(得分:6)

一项小改进 - 少一条指令

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

答案 2 :(得分:2)

现在可用。您可以使用_div128_udiv128

  

String pathName = new java.io.File(Application.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getName(); 内部函数将128位整数除以64位整数。返回值保存商,内部函数通过指针参数返回余数。 _div128是Microsoft专用的。

据说去年from "Dev16"可用,但我不确定是哪个版本。我猜它是VS 16.0 A.K.A VS2019,但是MSDN上的文档显示它可以更进一步地进入VS2015

答案 3 :(得分:1)

我不是专家,但我挖了这个:

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

有趣的东西。希望它有所帮助。

编辑:这也很有见地:http://www.gamedev.net/topic/508197-x64-div-intrinsic/