ehu*_*udt 5 c compiler-construction optimization compiler-optimization
整数除法/和模%运算通常在编程中一起使用,有时甚至在相同的操作数和后续行中使用.例如,下面的C函数是一个简单的函数,它将/2个数字的结果与它们的结果相加%,就是这样:
int sum2digits(int x, int base) {
int n, m;
n = x / base;
m = x % base;
return n + m;
}
Run Code Online (Sandbox Code Playgroud)
据我所知,双方/并%通过(在x86)的同一台机器的指令执行.说,如果为整数除法(执行机器指令div或idiv两个数字的),a和b,然后之后的值a / b将被存储在寄存器EAX,其余a % b在EDX.
我想知道编译器是否利用了这种质量并看了一下汇编代码.事实证明,使用gcc进行正常编译并不能优化:
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
Run Code Online (Sandbox Code Playgroud)
此汇编代码对idivl执行2次后续调用,但每次从另一个寄存器读取结果(商用EAX,余数为EDX).但是,通过-O更改图片进行编译:
mov %edi,%eax
mov %edi,%edx
sar $0x1f,%edx
idiv %esi
add %edx,%eax
retq
Run Code Online (Sandbox Code Playgroud)
此代码idiv只调用一次,并将其值用于两个计算.
为什么这种优化不是默认的?div连续两次调用有什么用?这种优化能否以任何方式改变程序的行为?
另外,也许更重要的是,作为程序员,有没有办法手动提取这两个值(商和余数),保证CPU只执行1个整数除法?
为什么这种优化不是默认的?
如果编译器和优化器是完美的,并且调试器可以对代码进行逆向工程,那么优化将成为普遍的默认设置。但是编译器并不总是生成正确的代码,优化器并不总是保留语义,调试器也不总是能够找出任何给定指令与优化程序的哪些部分相关。看起来您的编译器安装时已经预设了默认选项,以保证绝对安全和调试简单。
有没有办法手动提取这 2 个值(商和余数),保证 CPU 只执行 1 次整数除法?
如今,最好的方法正是您所做的:向编译器询问优化的代码。该div例程是从前几天遗留下来的,当时除法运算符的结果是为负数定义的实现,并且优化编译非常慢,以至于识别这样的事情最好手动完成。