Gcc 如何强制编译器在x86_64中生成ADOX/ADCX而不是ADC?

Gcc 如何强制编译器在x86_64中生成ADOX/ADCX而不是ADC?,gcc,assembly,x86-64,compiler-optimization,biginteger,Gcc,Assembly,X86 64,Compiler Optimization,Biginteger,Intel推出了ADCX、AODX以支持大整数运算,但仅使用一个函数很难生成ADCX/AODX:\u addcarryx\u u64 假设对于A和B的大整数加法,其中整数由uint64_t数组表示,分别由pa和pb表示。下面是一个可能的实现(pa和pb保持相同的长度n,为简单起见,结果溢出不是问题) #包括 使用肢体类型=uint64; 无效添加(常量肢体类型*\uuuuu限制\uuuuupa、常量肢体类型*\uuuu限制\uuuuuupb、肢体类型*\uuuuu限制\uuuuuuupr、无符号

Intel推出了ADCX、AODX以支持大整数运算,但仅使用一个函数很难生成ADCX/AODX:
\u addcarryx\u u64

假设对于A和B的大整数加法,其中整数由
uint64_t
数组表示,分别由
pa
pb
表示。下面是一个可能的实现(
pa
pb
保持相同的长度
n
,为简单起见,结果溢出不是问题)

#包括
使用肢体类型=uint64;
无效添加(常量肢体类型*\uuuuu限制\uuuuupa、常量肢体类型*\uuuu限制\uuuuuupb、肢体类型*\uuuuu限制\uuuuuuupr、无符号n){
无符号字符进位=0;
未签名的i;

对于(i=0;iAFAIK、gcc和clang在优化
\u addcarryx\u u64
方面都很糟糕,您无法让它们为您发出一个像样的asm循环。您可能仍然希望在内联asm中编写此循环(请确保使用
“memory”
clobber,并且不要修改仅输入的操作数)与adc相比,
adox
在这里根本没有帮助,实际上您需要的是一个
inc
dec/jnz
循环,使用LEA增加指针以避免干扰CF。这在现代CPU post P6系列上很好:
cmp
写入所有标志(包括OF和CF)这就是为什么
adox
/
adcx
没有帮助的原因。对于单个依赖链,您只需要
adc
。有些东西使CF保持不变,但任何与标志接触的循环方式都会破坏。@fuz:也许他们的意思是说Intel引入了ADX扩展(adcx+adox)。它的存在是为了允许在biginteger乘法中使用ILP,您实际上可以使用多个进位传播链:。或者,如果您并行执行两个单独的biginteger加法,则在两个链上执行交错操作。有几个现有答案涵盖了当前的GCC情况;我将它们链接为副本,尤其是m列表链接有问题。只有当您无法从intrinsics获得良好的asm时,才建议将内联asm作为最后手段,并且您可以花时间确保您获得了正确的约束,并且没有任何潜在的错误。但这是内联asm合理的少数情况之一:编译器(可能ICC除外)我也对这样展开循环感兴趣:。遗憾的是,GCC和ICC都没有像clang那样优化展开的版本。
        mov     rcx, QWORD PTR [rdi+rax]  # tmp106, MEM[base: pa_16(D), index: ivtmp.11_26, offset: 0B]
        add     r8b, -1   # carry: to set CF Flag for subsequent adc
        adc     rcx, QWORD PTR [rsi+rax]  # tmp106, MEM[base: pb_15(D), index: ivtmp.11_26, offset: 0B]
        mov     QWORD PTR [rdx+rax], rcx  #* ivtmp.11, tmp106
        setc    r8b     #, carry

        add     rax, 8    # ivtmp.11,
        cmp     r9, rax   # _20, ivtmp.11
        jne     .L3       #,