如何在C++中高效对模拟__int128_t的数组执行二进制补码取反?
AMD64架构下用
std::array<uint64_t,2>模拟__int128_t的高效补码取反实现 需求:使用std::array<uint64_t, 2> A模拟__int128_t类型(其中B = A[0] + 2^64 * A[1],A[0]为低64位,A[1]为高64位),需要实现高效的二进制补码取反操作。
已尝试方案
模拟
__int128_t取反的汇编指令:
观察到原生__int128_t取反对应的汇编指令序列为:negq %r12 adcq $0, %r13 negq %r13尝试用内联汇编复现该逻辑:
asm ( "negq %[low];" "adcq $0, %[high];" "negq %[high];" : [high] "+r"(A[1]), [low] "+r"(A[0]) );问题:代码周围产生大量冗余
mov指令,降低执行效率。使用
_subborrow_u64函数实现:
利用补码取反等价于0 - x的特性,通过_subborrow_u64处理进位:unsigned char carry = 0; carry = _subborrow_u64(carry, 0, A[0], &(A[0])); carry = _subborrow_u64(carry, 0, A[1], &(A[1]));问题:生成的汇编代码包含冗余操作,执行效率偏低。
高效实现方案
方案1:纯C++实现(依赖编译器优化)
基于补码取反的数学定义~x = -x - 1,结合128位值的拆分特性,写出如下代码。现代编译器(GCC/Clang/MSVC)开启-O2或更高优化级别时,会自动生成与原生__int128_t取反完全一致的最优汇编:
void negate(std::array<uint64_t, 2>& A) { uint64_t low = ~A[0] + 1; uint64_t high = ~A[1]; if (low == 0) { high += 1; } A[0] = low; A[1] = high; }
或者更简洁的进位处理写法:
void negate(std::array<uint64_t, 2>& A) { uint64_t carry = 1; A[0] = ~A[0] + carry; carry = (A[0] == 0) ? 1 : 0; A[1] = ~A[1] + carry; }
方案2:优化内联汇编
原内联汇编的冗余mov问题源于寄存器约束的灵活性不足,改进后的内联汇编添加标志寄存器约束,让编译器更好地处理上下文:
void negate(std::array<uint64_t, 2>& A) { asm volatile ( "negq %0;" "adcq $0, %1;" "negq %1;" : "+r"(A[0]), "+r"(A[1]) : : "cc" // 告知编译器条件标志寄存器被修改 ); }
不过更推荐依赖编译器自动优化,手动寄存器约束可能限制全局优化空间。
方案3:直接使用__int128_t(编译器支持时)
如果目标编译器支持__int128_t(如GCC/Clang),直接转换后取反再拆分是最简洁高效的方式,编译器会自动生成最优汇编:
void negate(std::array<uint64_t, 2>& A) { __int128_t val = static_cast<__int128_t>(A[1]) << 64 | A[0]; val = ~val; A[0] = static_cast<uint64_t>(val); A[1] = static_cast<uint64_t>(val >> 64); }
内容的提问来源于stack exchange,提问作者ohad
相关产品推荐
相关产品推荐

