整数除法/
和模%
运算经常在编程中一起使用,有时甚至在相同的操作数和后续行中。例如,下面的 C 函数是一个简单的函数,它将/
2 个数字的结果与它们的结果相加%
,它就是这样做的:
int sum2digits(int x, int base) {
int n, m;
n = x / base;
m = x % base;
return n + m;
}
据我所知,两者/
和%
都由相同的机器指令(在x86中)执行。比如说,如果您执行机器指令对两个数字和进行整数除法 (div
或) ,然后 的值将存储在寄存器 EAX 中,余数存储在 EDX 中。
我想知道编译器是否利用了这种质量并查看了汇编代码。事实证明,使用 gcc 进行正常编译并不会对此进行优化: idiv
a
b
a / b
a % b
push %rbp
mov %rsp,%rbp
mov %edi,-0x14(%rbp)
mov %esi,-0x18(%rbp)
mov -0x14(%rbp),%eax
mov %eax,%edx
sar $0x1f,%edx
idivl -0x18(%rbp)
mov %eax,-0x8(%rbp)
mov -0x14(%rbp),%eax
mov %eax,%edx
sar $0x1f,%edx
idivl -0x18(%rbp)
mov %edx,-0x4(%rbp)
mov -0x4(%rbp),%eax
mov -0x8(%rbp),%edx
add %edx,%eax
pop %rbp
retq
此汇编代码对 idivl 执行 2 次后续调用,但每次都从另一个寄存器读取结果(EAX 表示商,EDX 表示余数)。但是,编译时会-O
改变图片:
mov %edi,%eax
mov %edi,%edx
sar $0x1f,%edx
idiv %esi
add %edx,%eax
retq
此代码idiv
仅调用一次,并将其值用于两次计算。
为什么这种优化不是默认的?div
连续调用两次有什么用?这种优化能以任何方式改变程序的行为吗?
此外,也许更重要的是,作为程序员,有没有办法手动提取这 2 个值(商和余数),以保证 CPU 只执行 1 个整数除法?