我正在阅读此链接,简而言之,有人可以向一周前开始学习汇编 x86 和 64 位的人解释当前 C++ 编译器的问题吗?
不幸的是,当前的编译器没有优化 @craigster0 的良好可移植版本,因此如果您想利用 64 位 CPU,则不能使用它,除非作为没有 #ifdef 的目标的后备。(我没有看到优化它的通用方法;您需要 128 位类型或内在函数。)
为了澄清起见,我正在研究汇编的好处,当时我遇到人们在多篇文章中说,当前的编译器在 64 位乘法方面没有进行优化,因为它们使用最低部分,所以它们不执行完整的 64 位乘法什么是不是这个意思。那么,获得较高部分的含义是什么?我在一本书中读到,在 64 位架构中,只有最低 32 位用于 RFlags,这些相关吗?我很困惑吗?
大多数 CPU 允许您从两个操作数开始,每个操作数都是一个寄存器的大小,然后将它们相乘以获得填充两个寄存器的结果。
例如,在 x86 上,如果将两个 32 位数字相乘,您将在 EDX 中得到结果的高 32 位,在 EAX 中得到结果的低 32 位。如果将两个 64 位数字相乘,则会得到 RDX 和 RAX 中的结果。
在其他处理器上,使用其他寄存器,但适用相同的基本思想:一个寄存器乘以一个寄存器给出填充两个寄存器的结果。
C 和 C++ 没有提供利用该功能的简单方法。当您对小于 的类型进行操作时int,输入操作数将转换为int,然后将 int 相乘,结果为 int。如果输入大于 int,则它们作为相同类型相乘,结果也是相同类型。没有采取任何措施来考虑结果是输入类型的两倍,并且实际上地球上的每个处理器都会产生每个输入的两倍大的结果。
当然,有一些方法可以解决这个问题。最简单的是我们在小学学到的基本因式分解:将每个数字分解为上半部分和下半部分。然后我们可以将这些部分单独相乘:(a+b) * (c+d) = ac + ad + bc + bd。由于这些乘法中的每一个都只有一半的非零位,因此我们可以将每项算术作为半大小的运算来执行,产生全大小的结果(加上从加法中执行的单个位)。例如,如果我们想在 64 位处理器上进行 64 位乘法以获得 128 位结果,我们会将每个 64 位输入分解为 32 位部分。然后每次乘法都会产生 64 位结果。然后,我们将各个片段相加(使用适当的位移位)以获得最终的 128 位结果。
但是,正如 Peter 指出的那样,当我们这样做时,编译器不够聪明,无法意识到我们想要完成的任务,并将乘法和加法序列转换回单个乘法,产生的结果是每个输入的两倍。相反,它将表达式相当直接地转换为一系列乘法和加法,因此它花费的时间比单个乘法长大约四倍。