让编译器生成 adc 指令
Posted
技术标签:
【中文标题】让编译器生成 adc 指令【英文标题】:Getting a compiler to generate adc instruction 【发布时间】:2013-06-28 18:45:05 【问题描述】:有什么方法可以让 Clang、GCC 或 VS 仅使用 Standard-C++(98/11/14) 生成 adc(带进位相加)指令? (编辑:我的意思是在 x64 模式下,如果不清楚,请见谅。)
【问题讨论】:
那些是c
编译器
@Taylor:“GCC”和“Visual Studio”是编译器集合的名称,其中包含 C++ 编译器等。 clang
是一个 C++ 编译器。
您有什么特别的理由要这样做吗?
C 或 C++ 的全部意义在于将程序员与特定于平台的程序集隔离开来。 C 或 C++ 标准从未提及 ADC(这是一个实现细节),因此答案是否。无法保证特定处理器提供 ADC 指令...
@OliCharlesworth 是的,我想在 ISO-C++ 中实现高效的任意精度算术,但我认为目前不可能。
【参考方案1】:
如果您的代码进行比较并将比较结果添加到某物,则 gcc 5 通常会发出 adc
(顺便说一下,gcc 4.8 不会在此处发出 adc
)。例如,
unsigned foo(unsigned a, unsigned b, unsigned c, unsigned d)
return (a + b + (c < d));
组装到
foo:
cmpl %ecx, %edx
movl %edi, %eax
adcl %esi, %eax
ret
但是,让 gcc 真正发出 adc
有点棘手。
【讨论】:
是的,对于像上面这样的条件增量,很难让 gcc 发出adc
。我认为 gcc 有一个窥视孔或其他阶段,它采用adc
和0
立即并变成(在现代硬件上通常更糟)xor eax, eax; setb al; add ..., eax
序列。例如,如果你从上面删除b
,所以它是(a + (c < d))
,自然顺序是使用adc
和0
,但gcc 做了奇怪的setb
事情。对于像a += (c < d) ? 1 : 0
这样的三元表达式也是如此。但是,如果您使用a += (c < d) ? 3 : 2
或任何其他非一值,它确实 使用adc eax, 2
。
所以似乎只有当0
会立即出现这种奇怪现象。此外,如果您使用分支,例如if (c < d) a++
,它使用adc
!我试过many examples on godbolt。【参考方案2】:
在 GCC 上有一个 __int128_t
类型可用于 amd64 和其他 64 位目标,它将使用一对 add
/adc
指令进行简单的添加。 (请参阅下面的 Godbolt 链接)。
此外,这个纯 ISO C 代码可以编译为 adc:
uint64_t adc(uint64_t a, uint64_t b)
a += b;
if (a < b) /* should simplify to nothing (setting carry is implicit in the add) */
a++; /* should simplify to adc r0, 0 */
return a;
对我 (ARM) 来说,它产生了一些愚蠢的东西,但它针对 x86-64(在 Godbolt compiler explorer 上)编译为:
mov rax, rdi # a, a
add rax, rsi # a, b
adc rax, 0 # a,
ret
【讨论】:
我要补充一点,我认为-funsafe-math-optimizations
可能会杀死整个if
块,但似乎没有。不过,我认为 C 可能允许这样的优化,所以请注意。
无符号环绕在 C/C++ 中被明确定义为二进制整数。它保证正常工作。 -funsafe-math-optimizations
只影响浮点行为。也许您正在考虑有符号整数环绕是未定义的行为? -fwrapv
使其定义明确(作为 2 的补码),但默认情况下不启用。【参考方案3】:
如果您为 X86(C++ 11 中的 int64_t
)编译 64 位有符号加法,编译后的代码将包含 adc
指令。
编辑:代码示例:
int64_t add_numbers(int64_t x, int64_t y)
return x + y;
在 X86 上,加法是使用 add
指令后跟 adc
指令来实现的。在 X64 上,只使用了一条 add
指令。
【讨论】:
你能给出一个最小的示例函数吗?我从来没有在我的任何二进制文件中看到过它,只有 lea(q) 和类似的。 请看我的编辑,我之前应该包含这个。这里的背景是看看是否可以在 Standard-C++ 中构建高效的任意整数运算。 :)以上是关于让编译器生成 adc 指令的主要内容,如果未能解决你的问题,请参考以下文章