Visual c++ _使用MSVC和ICC添加Carry_u64和_addcarryx_u64

Visual c++ _使用MSVC和ICC添加Carry_u64和_addcarryx_u64,visual-c++,assembly,intrinsics,icc,adx,Visual C++,Assembly,Intrinsics,Icc,Adx,MSVC和ICC都支持内部函数\u addcarry\u u64和\u addcarryx\u u64 根据,这些应分别映射到adcx和adox。但是,通过查看生成的程序集,可以清楚地看到它们分别映射到adc和adcx,并且没有映射到adox的内在属性 此外,告诉编译器在Linux上使用ICC启用AVX2时使用/arch:AVX2或-march=core-AVX2也没有什么区别。 我不知道如何使用MSVC和ICC启用ADX 该列表使用ADX技术列出了\u addcarryx\u u64,而\u

MSVC和ICC都支持内部函数
\u addcarry\u u64
\u addcarryx\u u64

根据,这些应分别映射到
adcx
adox
。但是,通过查看生成的程序集,可以清楚地看到它们分别映射到
adc
adcx
,并且没有映射到
adox
的内在属性

此外,告诉编译器在Linux上使用ICC启用AVX2时使用
/arch:AVX2
-march=core-AVX2
也没有什么区别。 我不知道如何使用MSVC和ICC启用ADX

该列表使用ADX技术列出了
\u addcarryx\u u64
,而
\u addcarry\u u64
没有列出的技术。但是,MSVC文档中有关这些内部函数的链接直接指向《英特尔内部函数指南》,该指南与MSVC自己的文档和生成的程序集相矛盾

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

这对于MSVC来说有一定的意义,因为它不允许内联汇编。它应该提供一种使用
adc
的方法,就像它使用
\u addcarry\u u64
一样

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


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


\u addcarry\u u64
内部文档说明仅生成
adc
\u addcarryx\u u64
内部可产生
adcx
adox
。然而,在MSVC 2013和2015中,
\u addcarryx\u u64
仅产生
adcx
。ICC生产这两种产品。

它们映射到
adc
adcx
adox
。编译器根据您如何使用指令来决定要使用哪些指令。如果并行执行两个大整数加法,编译器将使用
adcx
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]);
}
无符号字符c1=0,c2=0
对于(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]);
}

与此相关,GCC目前不支持ADOX和ADCX。“目前”包括GCC 6.4(Fedora 25)和GCC 7.1(Fedora 26)。GCC有效地禁用了intrinsic,但它仍然通过在预处理器中定义
\uuuuuuuuuuuuu
来宣传支持。另见。非常感谢席若瑶发现这个问题。

根据GCC帮助邮件列表上的Uros Bizjak,GCC可能会。另见

关于ADOX和ADCX,Clang有自己的一系列问题。Clang3.9和4.0在尝试使用它们时崩溃。另见。根据Craig Topper的说法,它应该在Clang 5.0中修复


我很抱歉在MSVC问题下发布这些信息。这是搜索有关使用Intrinsic的信息时为数不多的点击之一。

ADOX和ADCX是从Broadwell开始引入的,那么如何让它与AVX2一起工作呢?@LưuVĩnhPhúc,非常好。如何使用MSVC和ICC启用
ADX
?在任何情况下,编译器仍然使用_addcarryx生成adcx_u64@LưuVĩnhPhúc,ICC 13.0.1(我从中使用)于2012年底发布,因此它可能不支持
ADX
。ICC现在达到了15.0.2。我认为如果没有启用ADX,那么MSVC和ICC都会使用
adc
\u addcarry\u u64
。这可以解释我所观察到的情况。如果
ADX
未启用(并且
\u addcarryx\u u64
应该生成
adox
而不是
adcx
),则编译应该会失败。我刚买了一台Skylake笔记本电脑,这是我开始玩的东西之一。在VS2015和ICC15上,
\u addcarry\u u64()
仅产生
adc
。在VS2015上,
\u addcarryx\u u64()
仅产生
adcx
,而从不产生
adox
。在ICC15上,
\u addcarryx\u u64()
可以根据编译器的判断生成
adcx
adox
。实际上,ICC15试图对其进行智能化处理,当它检测到存在多个进位链时,将生成
adox
。也就是说,它不是最优的,我第一次尝试内联汇编时就能够轻而易举地击败ICC15。但是,当您试图实现可变长度乘法时,操作的尺寸在运行时之前是未知的,您需要循环。和循环具有计数器,这些计数器将对标志寄存器进行缓冲。这意味着您需要保存和恢复这两个标志。这太糟糕了。我不知道如何使用ICC或MSVC启用
ADX
。我不确定ICC13是否支持它。也许您可以将示例的程序集输出添加到您的答案中?“我不知道如何使用ICC启用ADX…”-对于GCC、ICC和可能的Clang,请使用
-march=native
(如果是本机CPU功能),或添加
-madx
功能标志。相关,请参见。它不会在GCC 6.1下的
-O3
中生成
adcx
/
adox
“编译器根据您如何使用它们来决定要使用哪些指令…”-您认为4路进位加法是否会使编译器生成除序列化
adc
之外的其他指令?@jww:这看起来是adcx/adox的完美用例。但我认为编译器还不够聪明,无法充分利用这一优势。目前,它们支持生成正确代码的内在机制。也许在一年左右的时间里,他们会制作出既快速又正确的代码,而不需要修改源代码。注意clang3.8.1在这里确实使用了adcx,但是使用了一些非常糟糕的标志保存(sahf)和eax的push/pop(a