让GCC在没有内联汇编的情况下使用进位逻辑进行任意精度的算术?

让GCC在没有内联汇编的情况下使用进位逻辑进行任意精度的算术?,c,optimization,gcc,compiler-optimization,arbitrary-precision,C,Optimization,Gcc,Compiler Optimization,Arbitrary Precision,当使用任意精度的算术运算(例如512位整数)时,有没有办法让GCC使用ADC和类似指令而不使用内联汇编 第一眼看到GMP的源代码就可以看出,它们只是为每个受支持的平台提供了汇编实现 下面是我编写的测试代码,它从命令行添加两个128位的数字并打印结果。(灵感来源于mini gmp的附加内容): #包括 #包括 #包括 int main(int argc,字符**argv) { uint32_t a[4]; uint32_t b[4]; uint32_t c[4]; uint32_t进位=0; 对于

当使用任意精度的算术运算(例如512位整数)时,有没有办法让GCC使用ADC和类似指令而不使用内联汇编

第一眼看到GMP的源代码就可以看出,它们只是为每个受支持的平台提供了汇编实现

下面是我编写的测试代码,它从命令行添加两个128位的数字并打印结果。(灵感来源于mini gmp的附加内容):

#包括
#包括
#包括
int main(int argc,字符**argv)
{
uint32_t a[4];
uint32_t b[4];
uint32_t c[4];
uint32_t进位=0;
对于(int i=0;i<4;++i)
{
a[i]=strtoul(argv[i+1],NULL,16);
b[i]=strtoul(argv[i+5],NULL,16);
}
对于(int i=0;i<4;++i)
{
uint32_t aa=a[i];
uint32_t bb=b[i];
uint32_t r=aa+进位;
进位=(r<进位);
r+=bb;
进位+=(r
GCC-O3-std=c99
不会产生任何
adc
指令,如
objdump
所检查。我的gcc版本是
i686-pc-mingw32-gcc(gcc)4.5.2

gcc将使用进位标志,如果它可以看到它需要:
例如,在32位机器上添加两个
uint64\t
值时,这必须导致一个32位
ADD
加上一个32位
ADC
。但除了那些编译器被迫使用进位的情况外,可能无法说服它使用汇编语言。因此,通过有效地让GCC知道值的单个“组件”属于一起,使用可用的最大整数类型来允许GCC优化操作可能是有益的

对于简单加法,计算进位的另一种方法是查看操作数中的相关位,如:

uint32_t aa,bb,rr;
bool msbA, msbB, msbR, carry;
// ...

rr = aa+bb;

msbA = aa >= (1<<31); // equivalent: (aa & (1<<31)) != 0;
msbB = bb >= (1<<31);
msbR = rr >= (1<<31);


carry = (msbA && msbB) || ( !msbR && ( msbA || msbB) );
uint32_t aa、bb、rr;
bool msbA、msbB、msbR、进位;
// ...
rr=aa+bb;

msbA=aa>=(1不,不会那么容易发生(如果可能的话)。这就是GMP使用内联汇编的原因之一。@Mysticial:我同意,但我想提出这个问题以防万一。我在谷歌搜索中没有看到关于这个主题的有意义的讨论。是的,我完全知道你在说什么,因为我以前也尝试过同样的方法,但失败得很惨。GCC不仅无法做到,但MSVC和ICC都不会。简言之,它需要一个非常专业的编译器优化过程来检测意图——这是一个非常小的范围,没有编译器编写者会在这样的事情上浪费时间。@Mysticial,我让ICC使用
\u addcarry\u u64
inquired@Zboson ICC高效地完成了这项工作,而MSVC直到非常晚才拥有这一内在功能最近。(~1年前)使用更大的整数类型只会将问题推到更高的级别。除非GCC有512位整数类型,否则您仍然需要弄乱进位逻辑。当然,您迟早会计算自己的进位。但是当使用
uint64_t
而不是
uint32_t
时,例如,您将节省50%的进位“手动”进位标志计算及其处理时间。另一个便宜的技巧是只使用32位字中的31位(更好的是,64位中的63位)。您放弃了3%或更少的存储容量,但进位是在总和的MSB中为您计算的。顺便说一下,对于无符号类型
进位==((a+b)
。也许值得一看GCC的整数溢出内置功能:
uint32_t aa,bb,rr;
bool msbA, msbB, msbR, carry;
// ...

rr = aa+bb;

msbA = aa >= (1<<31); // equivalent: (aa & (1<<31)) != 0;
msbB = bb >= (1<<31);
msbR = rr >= (1<<31);


carry = (msbA && msbB) || ( !msbR && ( msbA || msbB) );