如何指示 MSVC 编译器使用 64 位/32 位除法而不是较慢的 128 位/64 位除法?

2023-11-24

如何告诉 MSVC 编译器使用 64 位/32 位除法运算来计算 x86-64 目标的以下函数的结果:

#include <stdint.h> 

uint32_t ScaledDiv(uint32_t a, uint32_t b) 
{
  if (a > b)
        return ((uint64_t)b<<32) / a;   //Yes, this must be casted because the result of b<<32 is undefined
  else
        return uint32_t(-1);
}

我想要代码,当if陈述正确,编译以使用 64 位/32 位除法运算,例如像这样的东西:

; Assume arguments on entry are: Dividend in EDX, Divisor in ECX
mov edx, edx  ;A dummy instruction to indicate that the dividend is already where it is supposed to be
xor eax,eax
div ecx   ; EAX = EDX:EAX / ECX

...但是x64 MSVC编译器坚持使用128位/64位div指令,例如:

mov     eax, edx
xor     edx, edx
shl     rax, 32                             ; Scale up the dividend
mov     ecx, ecx
div rcx   ;RAX = RDX:RAX / RCX

See: https://www.godbolt.org/z/VBK4R71

根据答案这个问题, 128位/64位div指令是不更快比 64 位/32 位div操作说明。

这是一个问题,因为它不必要地减慢了我的 DSP 算法,而该算法会产生数百万个这样的缩放除法。

我通过修补可执行文件以使用 64 位/32 位 div 指令来测试此优化:性能提升28%根据产生的两个时间戳rdtsc指示。

(编者注:大概是在最近的一些 Intel CPU 上。AMD CPU 不需要这种微优化,如链接的问答中所述。)


当前的编译器(gcc/clang/ICC/MSVC)不会从可移植的 ISO C 源代码中进行此优化,即使您让他们证明这一点b < a所以商将适合 32 位。 (例如使用 GNU Cif(b>=a) __builtin_unreachable(); 在戈德螺栓上)。这是一个错过的优化;在这个问题得到解决之前,您必须使用内在函数或内联汇编来解决它。

(或者使用 GPU 或 SIMD 代替;如果许多元素具有相同的除数,请参见https://libdivide.com/用于 SIMD 计算一次乘法逆元并重复应用它。)


_udiv64可用从 Visual Studio 2019 RTM 开始。

在 C 模式下(-TC)它显然总是被定义的。在C++模式下,你需要#include <immintrin.h>,根据 Microsoft 文档。或者intrin.h.

https://godbolt.org/z/vVZ25L (Or on Godbolt.ms because recent MSVC on the main Godbolt site is not working1.)

#include <stdint.h>
#include <immintrin.h>       // defines the prototype

// pre-condition: a > b else 64/32-bit division overflows
uint32_t ScaledDiv(uint32_t a, uint32_t b) 
{
    uint32_t remainder;
    uint64_t d = ((uint64_t) b) << 32;
    return _udiv64(d, a, &remainder);
}

int main() {
    uint32_t c = ScaledDiv(5, 4);
    return c;
}

_udiv64 将产生 64/32 div。左右两移是一个错过的优化。

;; MSVC 19.20 -O2 -TC
a$ = 8
b$ = 16
ScaledDiv PROC                                      ; COMDAT
        mov     edx, edx
        shl     rdx, 32                             ; 00000020H
        mov     rax, rdx
        shr     rdx, 32                             ; 00000020H
        div     ecx
        ret     0
ScaledDiv ENDP

main    PROC                                            ; COMDAT
        xor     eax, eax
        mov     edx, 4
        mov     ecx, 5
        div     ecx
        ret     0
main    ENDP

所以我们可以看到 MSVC 并没有通过_udiv64,即使在这种情况下它不会溢出并且它可以编译main只是mov eax, 0ccccccccH / ret.


更新#2 https://godbolt.org/z/n3Dyp-添加了使用英特尔 C++ 编译器的解决方案,但这效率较低,并且会破坏常量传播,因为它是内联汇编。

#include <stdio.h>
#include <stdint.h>

__declspec(regcall, naked) uint32_t ScaledDiv(uint32_t a, uint32_t b) 
{
    __asm mov edx, eax
    __asm xor eax, eax
    __asm div ecx
    __asm ret
    // implicit return of EAX is supported by MSVC, and hopefully ICC
    // even when inlining + optimizing
}

int main()
{
    uint32_t a = 3 , b = 4, c = ScaledDiv(a, b);
    printf( "(%u << 32) / %u = %u\n", a, b, c);
    uint32_t d = ((uint64_t)a << 32) / b;
    printf( "(%u << 32) / %u = %u\n", a, b, d);
    return c != d;
}

脚注 1:Matt Godbolt 的主站点的非 WINE MSVC 编译器暂时(?)消失了。微软运行https://www.godbolt.ms/在真实 Windows 上托管最新的 MSVC 编译器,并且通常主要的 Godbolt.org 站点会转发到 MSVC 的站点。)

看来godbolt.ms会生成短链接,但不会再次扩展它们!无论如何,完整链接更好地抵抗链接腐烂。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何指示 MSVC 编译器使用 64 位/32 位除法而不是较慢的 128 位/64 位除法? 的相关文章

随机推荐

  • 如何使用 EPPLus 修改图表系列?

    我想问一下如何使用 EPPLUS 库更新 Excel 中现有图表的系列值 我还不知道该怎么做 我已经成功创建图表 但仍然无法更新系列值 任何人都可以给我提供一些示例代码或参考链接吗 抱歉这么晚才回答 在搜索其他内容时看到您的帖子 如果图表有
  • vscode "python.jediEnabled": false,显示为未知配置设置

    这是settings json文件代码 python autoComplete addBrackets true python linting enabled true python pythonPath C Program Files P
  • 一次一密,加密解密

    我正在尝试学习密码学并且一直在尝试这个练习 编写一个程序 最好是Java 生成一次性的pad 这是所有文件中比较大的一个 随机数据 例如 1 MB 该程序还应该能够根据以下内容加密 解密文件 生成一次性本 提示 使用以下测试向量来检查您的程
  • 使用 C# 将日期时间格式转换为 SQL 格式

    我正在尝试从 C 保存当前日期时间格式并将其转换为 SQL Server 日期格式 如下所示yyyy MM dd HH mm ss所以我可以用它来我的UPDATE query 这是我的第一个代码 DateTime myDateTime Da
  • 找不到 -lboost_system 的库

    我使用 macports 安装了 boost 这些文件似乎位于 opt local include boost 中 我的 makefile 不再工作并且出现以下错误 Undefined symbols boost system generi
  • 在 C# 中以编程方式设置 dllimport

    我在用DllImport在我的解决方案中 我的问题是我有同一个 DLL 的两个版本 一个是为 32 位构建的 另一个是为 64 位构建的 它们都公开具有相同名称和相同签名的相同函数 我的问题是我必须使用两个静态方法来公开这些方法 然后在运行
  • 如何使用 ember-rails 启用 query-params-new 功能

    我在使用 query params new 功能时遇到问题 我的 ember 版本是 1 4 0 beta 2 Ember js 通过 ember rails 和 ember source gems 加载到我的 Rails 应用程序中 在初
  • 从模板(视图)中动态加载 AngularJS 模块

    背景 为了便于讨论 我们假设您有 100 000 次观看 部分观看 我们还假设您有附带的视图范围控制器 以及潜在的视图范围服务和过滤器 尝试设想一个托管 100 000 个不同小型应用程序的聚合应用程序 Issue 当您有需要附带控制器的
  • ASP.NET MVC 忽略所有 url 末尾的“.html”

    我是 ASP NET MVC 新手 现在正在努力解决 url 路由问题 我正在使用 asp net mvc 3 RC2 如何创建一个 url 路由IGNORESurl 中最末尾的扩展名 扩展名可以是 html aspx php anythi
  • 如何实现类似于 jQuery UI 自动完成的 Dojo 自动完成?

    美好的一天 我使用 JSP 和 jQuery UI 成功实现了文本输入的自动完成功能 自动完成数据从数据库中检索并通过服务器端的 q 参数进行过滤 它返回包含查询字符串的所有项目 SELECT name FROM organization
  • NHibernate 代理的 JSON.Net 序列化 (NH 3.3.2.4000)

    I m still让 Json Net 和 NHibernate 很好地协同工作一直存在困难 即 让 Json NET 序列化代理的 NHibernate 对象 我已遵循建议here 无论是已接受的答案还是修正案 但没有骰子 上述解决方案的
  • 具有多个构造函数的 MEF 构造函数参数

    我开始使用 MEF 并且我有一个具有多个构造函数的类 如下所示 Export typeof ifoo class foo ifoo void foo ImportingConstructor void foo object par1 我在用
  • 如何连接 WAMP 服务器上的 MySQL?

    这对你来说可能非常简单 但我已经为此奋斗了一个小时 这是我尝试运行的代码 您可以看到我使用 8080 作为端口号 当然 我也有 HTML 代码 但是 每当我尝试打开 PHP 文件时 它都会显示以下错误消息 Warning mysql con
  • 按比例缩放 HTML 以完全适合 PDF A4 尺寸

    我正在使用 PHP Mysql jQuery 我有一个网页需要转换为高分辨率 A4 尺寸的 PDF http optisolbusiness com funeral site sample index id 255 我已使用以下方法将 HT
  • WindowsError:[错误 5] 尝试终止子进程时访问被拒绝 (python)

    所以我有一个 python 脚本 它运行一个循环 在该循环中它通过 subprocess Popen 调用程序 A 等待其输出 然后保存输出 然后再次调用它 依此类推 在我设置为输入的多次运行中 这种情况不断发生 问题是我有一个计时器 这样
  • 使用 WSDL (SOAP) 将 PayPal 集成到 C#/.NET 解决方案中

    环境 Visual Studio 2010 专业版 NET框架4 C 使用以下 WSDL 添加了服务参考 https www paypalobjects com wsdl PayPalSvc wsdl 问题1 像这样简单编译时 从 Refe
  • Scikit-Learn 决策树:预测为 a 或 b 的概率?

    我有一个带有 Scikit Learn 的基本决策树分类器 Used to determine men from women based on height and shoe size from sklearn import tree he
  • 强制 GVim 在关闭前提示

    我最近一直在过渡到 GVim 因为我发现它比终端中的 vim 更美观 而且速度更快一些 我有一个非常坏的习惯 我正在努力改掉 当我从命令行使用 vim 时 我的工作流程是这样的 vim filename txt make some edit
  • 如何在 R 中绘制 3D 堆叠直方图?

    我想在 R 中绘制堆积直方图 即在三维中堆叠各个直方图 感谢大家的建议 尤其是 Shane 的建议 hadley 我同意你的观点 但是 我的情况有所不同 我试图通过绘制四个堆叠直方图来传达的要点是尾部变化很大 将被遮挡的部分没有任何后果在我
  • 如何指示 MSVC 编译器使用 64 位/32 位除法而不是较慢的 128 位/64 位除法?

    如何告诉 MSVC 编译器使用 64 位 32 位除法运算来计算 x86 64 目标的以下函数的结果 include