用__uint128_t替代GCC汇编divq指令失败,求解决方法
为什么用__uint128_t实现128位除法没有生成divq指令?
问题背景
我成功用__uint128_t实现了64×64乘法等128位运算,GCC生成的汇编和手写汇编完全一致,但在128位除法场景下,替换汇编代码遇到问题:
原汇编实现:
#include <stdint.h> void div64(uint64_t low, uint64_t high, uint64_t divisor, uint64_t& quotient, uint64_t& remainder) { asm("divq %2" : "+a"(low), "+d"(high) : "rm"(divisor)); quotient = low; remainder = high; }
我尝试用纯C/C++代码替换:
void div64(uint64_t low, uint64_t high, uint64_t divisor, uint64_t& quotient, uint64_t& remainder) { __uint128_t val = __uint128_t(low) | (__uint128_t(high) << 64); quotient = val / divisor; remainder = val % divisor; }
即使在-O3优化模式下,编译器也未生成单条divq指令,反而生成了包含__udivti3库调用的冗长汇编,同时通过乘法和减法计算余数。
原因分析
- x86架构的
divq指令可在单次操作中同时输出商(存于RAX寄存器)和余数(存于RDX寄存器),但GCC对__uint128_t的除法(/)和取余(%)操作默认是独立处理的:val / divisor会调用__udivti3库函数计算商;val % divisor则通过val - (val / divisor) * divisor的公式推导余数,而非直接复用divq指令的余数结果。
- 编译器优化器未自动将这两个操作合并为一次
divq调用,导致生成冗余的库函数调用和计算逻辑。
解决方案
使用GCC内置函数__builtin_udivmodti4,该函数专门用于同时计算128位无符号整数的商和余数,会直接生成divq指令,避免库函数调用:
#include <stdint.h> void div64(uint64_t low, uint64_t high, uint64_t divisor, uint64_t& quotient, uint64_t& remainder) { __uint128_t dividend = (__uint128_t)high << 64 | low; __uint128_t rem; // __builtin_udivmodti4(被除数, 除数, 余数输出指针) 返回商 quotient = (uint64_t)__builtin_udivmodti4(dividend, divisor, &rem); remainder = (uint64_t)rem; }
该代码在-O3优化下会生成与手写汇编完全一致的divq指令,同时保持代码的可移植性(Clang也支持此内置函数)。
内容的提问来源于stack exchange,提问作者Henrique Bucher
相关产品推荐
相关产品推荐

