使用intel内联汇编器编码带有进位的bigint add

2023-12-01

我想做一个快速代码来添加大整数中的 64 位数字:

uint64_t ans[n];
uint64_t a[n], b[n]; // assume initialized values....
for (int i = 0; i < n; i++)
  ans[i] = a[i] + b[i];

但以上不适用于进位。

我在这里看到另一个问题,建议使用 if 语句来检查哪个是优雅的:

ans[0] = a[0] + b[0];
int c = ans[0] < a[0];
for (int i = 0; i < n; i++) {
  ans[i] = a[i] + b[i] + c;
  c = ans[i] < a[i];
}

但是,我想学习如何嵌入内联(英特尔)汇编并更快地完成。 我确信有 64 位操作码,相当于:

add eax, ebx
adc ...

但我不知道如何将参数从 C++ 代码的其余部分传递给汇编器。


但以上不适用于进位。

如果您的意思是 GCC 不会生成使用ADC指令,那是因为它的优化器已经确定有一个更优化的方法来实现加法。

这是我的代码的测试版本。我已经将数组提取出来作为传递给函数的参数,这样代码就不能被省略,我们可以将我们的研究限制在相关部分。

void Test(uint64_t* a, uint64_t* b, uint64_t* ans, int n)
{
    for (int i = 0; i < n; ++i)
    {
        ans[i] = a[i] + b[i];
    }
}

现在,确实,当您使用现代版本的 GCC 编译它并看拆解,你会看到一堆看起来很疯狂的代码。

Godbolt 编译器资源管理器非常有用,它对 C 源代码行及其相应的汇编代码进行颜色编码(或者至少,它尽其所能;这在优化代码中并不完美,但它工作得足够好这里)。紫色代码是在循环内部实现 64 位加法的代码。 GCC 正在发出 SSE2 指令来进行加法。具体来说,你可以挑选MOVDQU(它将双四字从内存未对齐地移动到 XMM 寄存器中),PADDQ(对压缩整数四字进行加法),以及MOVQ(将一个四字从 XMM 寄存器移动到内存中)。粗略地说,对于非汇编专家来说,MOVDQU是它加载 64 位整数值的方式,PADDQ进行加法,然后MOVQ存储结果。

导致此输出特别嘈杂和令人困惑的部分原因是 GCC 是展开 the for环形。如果禁用循环展开(-fno-tree-vectorize), 你得到更容易阅读的输出,尽管它仍然使用相同的指令做同样的事情。 (嗯,主要是。现在它正在使用MOVQ到处,对于加载和存储,而不是加载MOVDQU.)

另一方面,如果您明确禁止编译器使用 SSE2 指令(-mno-sse2), 您会看到输出明显不同。现在,因为它无法使用 SSE2 指令,所以它发出基本的 x86 指令来执行 64 位加法,而唯一的方法是ADD + ADC.

我怀疑这就是你的代码期待查看。显然,GCC 认为向量化操作会产生更快的代码,因此当您使用-O2 or -O3旗帜。在-O1,它总是使用ADD + ADC。这是指令较少并不意味着代码速度更快的情况之一。 (或者至少,GCC 不这么认为。实际代码的基准测试可能会讲述不同的故事。开销在某些人为场景中可能很大,但在现实世界中无关紧要。)

就其价值而言,Clang 的行为方式与 GCC 的行为方式非常相似。


如果您的意思是此代码不会将前一个加法的结果传递到下一个加法,那么您是对的。您显示的第二段代码实现了该算法,并且GCC 确实使用ADC操作说明.

至少,以 x86-32 为目标时是这样。当针对 x86-64 时,您有可用的本机 64 位整数寄存器,甚至不需要“进位”;simple ADD说明就足够了,要求显著地更少的代码。事实上,这只是 32 位架构上的“bigint”算术,这就是为什么我在前面的所有分析和编译器输出中都假设 x86-32。

在评论中,Ped7g 想知道为什么编译器似乎没有这个想法ADD+ADC连锁成语。我不完全确定他在这里指的是什么,因为他没有分享他尝试过的输入代码的任何示例,但正如我所展示的,编译器do use ADC说明请参见此处。但是,编译器不会跨循环迭代链接进位。这在实践中很难实现,因为有太多指令清除标志。手写汇编代码的人也许能够做到这一点,但编译器却做不到。

(注意c可能应该是一个unsigned整数以鼓励某些优化。在这种情况下,它只是确保 GCC 使用XOR准备进行 64 位加法而不是CDQ。虽然速度稍快,但不是huge改进,但里程可能会因实际代码而异。)

(此外,令人失望的是 GCC 无法发出用于设置的无分支代码c循环内部。如果输入值足够随机,分支预测就会失败,最终会得到效率相对较低的代码。几乎可以肯定有一些方法可以编写 C 源代码来说服 GCC 发出无分支代码,但这是一个完全不同的答案。)


我想学习如何嵌入内联(英特尔)汇编并做得更快。

好吧,我们已经看到,如果你天真地引起了一堆,它可能不一定会更快ADC发出的指令。除非您确信对性能的假设是正确的,否则不要手动优化!

此外,内联汇编不仅难以编写、调试和维护,而且甚至可能使代码变慢,因为它抑制了编译器本来可以完成的某些优化。您需要能够证明您的手工编码的程序集相对于编译器生成的程序集具有足够显着的性能优势,因此这些考虑因素变得不那么重要。您还应该确认没有办法让编译器生成接近理想输出的代码,无论是通过更改标志还是巧妙地编写 C 源代码。

But 如果你真的想,您可以阅读各种在线教程,教您如何使用 GCC 的内联汇编器。这是一个相当不错的;还有很多其他的。当然,还有手册。一切都会解释如何“扩展汇编”允许您指定输入操作数和输出操作数,这将回答您的问题“如何从 C++ 代码的其余部分将参数传递给汇编器”。

正如 Paddy 和 Christopher Oicles 所建议的,您应该更喜欢内在函数而不是内联汇编。不幸的是,没有任何内在因素会导致ADC发出的指令。内联汇编是您唯一的资源,或者我已经建议编写 C 源代码,以便编译器能够自行执行 Right Thing™。

_addcarry_u32 and _addcarry_u64内在函数, 尽管。这些导致ADCX or ADOX发出的指令。这些是“扩展”版本ADC可以生成更高效的代码。它们是 Intel ADX 指令集的一部分,随 Broadwell 微架构一起引入。在我看来,Broadwell 的市场渗透率还不够高,您可以简单地发布ADCX or ADOX说明并到此为止。Lots的用户仍然拥有旧机器,尽可能支持它们符合您的利益。如果您正在准备针对特定架构进行调整的构建,那么它们非常有用,但我不建议将其用于一般用途。


我确信有 64 位操作码,相当于:add+adc

有 64 位版本ADD and ADC (and ADCX and ADOX)当您针对 64 位架构时。这将允许您使用相同的模式实现 128 位“bigint”算术。

在 x86-32 上,基本指令集中没有这些指令的 64 位版本。您必须转向 SSE2,就像我们看到 GCC 和 Clang 所做的那样。

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

使用intel内联汇编器编码带有进位的bigint add 的相关文章

  • WPF DataGrid 多选

    我读过几篇关于这个主题的文章 但很多都是来自 VS 或框架的早期版本 我想做的是从 dataGrid 中选择多行并将这些行返回到绑定的可观察集合中 我尝试创建一个属性 类型 并将其添加到可观察集合中 它适用于单个记录 但代码永远不会触发多个
  • 在 xaml 中编写嵌套类型时出现设计时错误

    我创建了一个用户控件 它接受枚举类型并将该枚举的值分配给该用户控件中的 ComboBox 控件 很简单 我在数据模板中使用此用户控件 当出现嵌套类型时 问题就来了 我使用这个符号来指定 EnumType x Type myNamespace
  • 没有特殊字符的密码验证器

    我是 RegEx 的新手 已经进行了大量搜索 但没有找到任何具体内容 我正在编写一个验证密码字符串的正则表达式 可接受的字符串必须至少具有 4 种字符类型中的 3 种 数字 小写字母 大写字母 特殊字符 我对包含有一个想法 也就是说 如果这
  • 在一个数据访问层中处理多个连接字符串

    我有一个有趣的困境 我目前有一个数据访问层 它必须与多个域一起使用 并且每个域都有多个数据库存储库 具体取决于所调用的存储过程 目前 我只需使用 SWITCH 语句来确定应用程序正在运行的计算机 并从 Web config 返回适当的连接字
  • 随着时间的推移,添加到 List 变得非常慢

    我正在解析一个大约有 1000 行的 html 表 我从一个字符串中添加 10 个字符串 td 每行到一个list td
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • -webkit-box-shadow 与 QtWebKit 模糊?

    当时有什么方法可以实现 webkit box shadow 的工作模糊吗 看完这篇评论错误报告 https bugs webkit org show bug cgi id 23291 我认识到这仍然是一个问题 尽管错误报告被标记为RESOL
  • 对类 static constexpr 结构的未定义引用,g++ 与 clang

    这是我的代码 a cp p struct int2 int x y struct Foo static constexpr int bar1 1 static constexpr int2 bar2 1 2 int foo1 return
  • 人脸 API DetectAsync 错误

    我想创建一个简单的程序来使用 Microsoft Azure Face API 和 Visual Studio 2015 检测人脸 遵循 https social technet microsoft com wiki contents ar
  • 结构体的内存大小不同?

    为什么第一种情况不是12 测试环境 最新版本的 gcc 和 clang 64 位 Linux struct desc int parts int nr sizeof desc Output 16 struct desc int parts
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • C# 动态/expando 对象的深度/嵌套/递归合并

    我需要在 C 中 合并 2 个动态对象 我在 stackexchange 上找到的所有内容仅涵盖非递归合并 但我正在寻找能够进行递归或深度合并的东西 非常类似于jQuery 的 extend obj1 obj2 http api jquer
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • 编译时展开 for 循环内的模板参数?

    维基百科 here http en wikipedia org wiki Template metaprogramming Compile time code optimization 给出了 for 循环的编译时展开 我想知道我们是否可以
  • 在 WPF 中使用 ReactiveUI 提供长时间运行命令反馈的正确方法

    我有一个 C WPF NET 4 5 应用程序 用户将用它来打开某些文件 然后 应用程序将经历很多动作 读取文件 通过许多插件和解析器传递它 这些文件可能相当大 gt 100MB 因此这可能需要一段时间 我想让用户了解 UI 中发生的情况
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • 对于某些 PDF 文件,LoadIFilter() 返回 -2147467259

    我正在尝试使用 Adob e IFilter 搜索 PDF 文件 我的代码是用 C 编写的 我使用 p invoke 来获取 IFilter 的实例 DllImport query dll SetLastError true CharSet
  • 当文件流没有新数据时如何防止fgets阻塞

    我有一个popen 执行的函数tail f sometextfile 只要文件流中有数据显然我就可以通过fgets 现在 如果没有新数据来自尾部 fgets 挂起 我试过ferror and feof 无济于事 我怎样才能确定fgets 当
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲

随机推荐

  • Swift、SpriteKit:如何保存场景的整个进度

    我用 GameViewController swift 构建了一个快速游戏 import UIKit import SpriteKit class GameViewController UIViewController override f
  • XMLHttpRequest 上传进度未正确触发

    我正在尝试使用 XMLHttpRequest 发送文件 该文件正在工作 但我的进度监视器不工作 我尝试上传 700KB 文件和 3MB 文件 但遇到了同样的问题 progress 事件触发一次 并且仅触发一次 并且它表示 event loa
  • 如何使用 Google Cloud Vision API 读取一列文本

    我有下一个文档图像 当我尝试将图像转换为文本时 结果是这样的 Top Text Ref Rad Dte Ddo Ejecutivo 76520400300 Banco de Bogot Luz Adriana Bottom Text 问题是
  • Axios,向 Flask 发出 POST 请求

    我尝试使用 axios 向 Flask 服务器发送 POST var config headers Content Type application json Access Control Allow Origin axios post h
  • 静音 3D 触摸 快速操作

    由于新 iPhone 6s 6s 具有新的 3D Touch 功能 我正在尝试向我的应用程序添加一些主屏幕快速操作 我能够实现正常的力流 触摸主屏幕中的应用程序图标 gt 选择可用的快速操作之一 gt 在所有可能的应用程序状态下正确处理它
  • REPL、解释器和编译器之间的关系

    From 维基百科 REPL 通常被误称为 口译员 这是一个用词不当 很多 使用的编程语言 编译 包括字节码 编译 有 REPL 例如 Common Lisp 和 Python From 对此帖子的回复 交互式解释器使用 REPL 一个 口
  • 在 PHP 中动态访问类常量

    我希望能够动态查找常量的值 但使用变量不适用于语法 gives apple banana orange Fatal error Access to undeclared static property Food type 如何动态调用常量
  • 在 AppEngine Python 上使用 Reportlab 生成的 PDF 文档中添加图像文件的正确方法

    我正在尝试使用 App Engine Python 上的 reportlab 生成 PDF 报告 但我不知道如何正确附加图像 图像是静态的 这是我的项目的目录树 这就是我所做的 在 奇帕斯 py 获取图像 im Image static l
  • python脚本的CPU使用率

    是否可以检查简单脚本的CPU使用率 例如 如何获取打印 100 次 hello world 的 CPU 使用率 以百分比表示 目前我正在控制台中获取执行时间 方法是 time p python script py 如果你使用的是 UNIX
  • php 包含文件包含

    我正在一个网站上工作 并被要求包含位于我的 php 脚本上方的文件夹中的文件 问题是那些我被要求包含的 php 文件包含在其中 因此 在调用我的 php 页面时找不到它们引用的文件 处理这种情况的最佳方法是什么 将文件从文件夹 B 包含到文
  • 将客户端证书设置为 Java HTTP 连接中的请求属性?

    我有一个 Java 应用程序 它通过带有 SSL 的套接字连接到另一个 Java 应用程序 因此我的客户端 JVM 已经具有 Djavax net ssl keyStore and Djavax net ssl trustStore属性设置
  • 如何在延迟着色中从光照几何体的内部进行绘制

    我正在尝试使用 OpenGL 和 GLSL 实现延迟着色器 但我在处理光照几何时遇到了问题 这些是我正在采取的步骤 Bind multitarget framebuffer Render color position normal and
  • 访问 Service 中的请求范围 Bean

    我有一颗普通豆 它是 a Scope request 或 b 放置在HttpServletRequest通过过滤器 拦截器 如何在 a 中访问这个 bean Service哪一种是应用程序范围的单例 这样做的原因是 因为我有一个自定义对象R
  • 使用 Heroku 设置 Paperclip Amazon S3

    has attached file image storage gt s3 s3 credentials gt RAILS ROOT config s3 yml path gt style filename 我不知道什么 path gt s
  • 缺少 1 个必需的位置参数:'self'

    这是我的代码 class Email Stuff def init self self emailaddr None self recipaddr None self EmailUser None self EmailPass None d
  • 如何确定文本节点中被点击的字符?

    我可以设置一个事件侦听器来告诉我 HTML 文档中某个位置何时发生鼠标单击 但是 如果单击发生在某些文本上 我需要知道单击发生在文本中的哪个字符上 有没有办法做到这一点 我能想到一些非常令人讨厌的解决方案 例如 对于文档中的每个字符 我可以
  • HttpClient上传大文件并显示发送的字节数

    我找到了这个代码示例 import org apache http params CoreProtocolPNames import org apache http util EntityUtils public class PostFil
  • 从 Excel 将超过 65.535 行导入到 MS Access

    我正在运行以下代码将整个工作表从 Excel 导入到 Access 该工作表有 77k 行 但 Access 仅导入 65 535 行 关于如何修复它有任何疑问吗 Excel 和 Access 都是 2013 版本 Function imp
  • 为什么我们需要将 MDSYS.ST_GEOMETRY 视为 ST_LINESTRING 才能使用 ST_PointN(1)?

    MDSYS ST GEOMETRY 甲骨文18c 以下查询有效 它从 MDSYS ST GEOMETRY 中提取第一个点 Source https www spdba com au using oracles st geometry typ
  • 使用intel内联汇编器编码带有进位的bigint add

    我想做一个快速代码来添加大整数中的 64 位数字 uint64 t ans n uint64 t a n b n assume initialized values for int i 0 i lt n i ans i a i b i 但以