9

MSVC 和 ICC 都支持内在函数_addcarry_u64_addcarryx_u64.

根据英特尔的内在指南白皮书,这些应该分别映射到adcxadox。但是,通过查看生成的程序集,很明显它们分别映射到adcadcx,并且没有内在的映射到adox.

此外,告诉编译器/arch:AVX2MSVC中启用 AVX2或-march=core-avx2在 Linux 上使用 ICC 没有区别。 我不确定如何使用 MSVC 和 ICC 启用 ADX。

MSVC的文档列出_addcarryx_u64了 ADX 的技术,而_addcarry_u64没有列出的技术。但是,MSVC 文档中这些内在函数的链接直接指向 Intel Intrinsic 指南,该指南与 MSVC 自己的文档和生成的程序集相矛盾。

由此我得出结论,英特尔的内在指南和白皮书是错误的。

这对于 MSVC 来说是有意义的,因为它不允许内联汇编,它应该提供一种使用adc它的方法_addcarry_u64

adcxand的一大优点adox是它们在不同的标志(进位CF和溢出OF)上运行,这允许两个独立的并行进位链。但是,既然没有内在的东西,adox这怎么可能呢?使用 ICC 至少可以使用内联汇编,但对于 64 位模式的 MSVC,这是不可能的。


微软和英特尔的文档(白皮书和在线内部指南)现在都同意了。

_addcarry_u64内在文档说只adc生产. _addcarryx_u64内在函数可以产生adcx或。adox但是,使用 MSVC 2013 和 2015,_addcarryx_u64只能生成adcx. ICC同时生产。

4

2 回答 2

5

它们映射到adc, adcxAND adox。编译器根据您使用它们的方式决定使用哪些指令。如果您并行执行两个大整数加法,编译器将使用adcxand adox,以获得更高的吞吐量。例如:

unsigned char c1 = 0, c2 = 0
for(i=0; i< 100; i++){ 
    c1 = _addcarry_u64(c1, res[i], a[i], &res[i]);
    c2 = _addcarry_u64(c2, res[i], b[i], &res[i]);
}
于 2015-03-24T18:04:46.900 回答
5

相关,GCC 目前不支持 ADOX 和 ADCX。“目前”包括 GCC 6.4 (Fedora 25) 和 GCC 7.1 (Fedora 26)。__ADX__GCC 有效地禁用了内在函数,但它仍然通过在预处理器中定义来宣传支持。另请参阅问题 67317,_addcarry_u32/_addcarry_u64 的愚蠢代码生成。非常感谢席若瑶找到问题。

根据 GCC 帮助邮件列表上的 Uros Bizjak,GCC 可能永远不会支持内在函数。另请参阅GCC 不会为 _addcarryx_u64 生成 ADCX 或 ADOX

Clang 在 ADOX 和 ADCX 方面有自己的一组问题。尝试使用 Clang 3.9 和 4.0 时会崩溃。另请参阅问题 34249,Panic when using _addcarryx_u64 with Clang 3.9。根据 Craig Topper 的说法,它应该在 Clang 5.0 中修复。

对于在 MSVC 问题下发布信息,我深表歉意。这是搜索有关使用内在函数的信息时为数不多的命中之一。

于 2017-08-21T11:58:46.587 回答