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

cxx*_*xxl 10 integer-division intrinsics visual-c++ 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位整数的支持会解决我的问题.

编辑:答案是否定的,Visual Studio 2010或2012中没有_udiv128内在函数.

Ale*_*nze 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;
}
Run Code Online (Sandbox Code Playgroud)

  • 对于MSVC,可以在编译过程中使用#pragma节将这些函数放入代码段中 (2认同)
  • 强烈推荐 `const unsigned char code[]`;你希望它是“const”,所以它放在“.rdata”中。我不知道它是否已经位于代码部分旁边并因此可执行,就像 Linux/ELF 上的 TEXT 段中的“.rodata”一样,但它应该有帮助。并使函数指针为“const”或静态 const(或 constexpr),这样它们就可以(希望)被优化掉,而不是编译为实际的内存间接调用。**将它们放入数组中与单独编译的“.asm”文件相比确实没有任何好处。**如果调用编译为间接调用,则纯粹是缺点。 (2认同)

小智 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
Run Code Online (Sandbox Code Playgroud)


phu*_*clv 5

现在可以使用了。您可以使用_div128_udiv128

_div128内在函数将 128 位整数除以 64 位整数。返回值保存商,内在函数通过指针参数返回余数。_div128是微软特有的。

去年据说可以从“Dev16”获得,但我不确定是哪个版本。我猜它是 VS 16.0 AKA VS2019,但 MSDN 上的文档显示它更进一步到 VS2015


Dan*_*cek 2

我不是专家,但我发现了这一点:

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

有趣的东西。希望能帮助到你。

编辑:这也很有洞察力:http ://www.gamedev.net/topic/508197-x64-div-intrinsic/