大佬教程收集整理的这篇文章主要介绍了c – 早期if语句的函数中不需要的弹出指令,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
int a(int* a,int* b) { if (b - a < 2) return *a = ~*a; // register intensive code here e.g. sorTing network }
将(-O2 / -O3)编译成这样的东西:
push r15 mov rax,rcx push r14 sub rax,rdx push r13 push r12 push rbp push rbx sub rsp,184 mov QWORD PTR [rsp],rdx cmp rax,7 jg .L95 not DWORD PTR [rdx] .L162: add rsp,184 pop rbx pop rbp pop r12 pop r13 pop r14 pop r15 ret
这显然在b-a<的情况下具有巨大的开销. 2.如果-Os gcc编译为:
@H_803_2@mov rax,rcx sub rax,7 jg .L74 not DWORD PTR [rdx] ret .L74:编译器有没有理由这样做?有没有办法让他们编译到较短的版本而不编译大小?
这是an example on Godbolt再现这个.它似乎与递归的复杂部分有关
将早期检查拉入包装器通常很有用,因为它足够小,可以内联.
看起来现代gcc实际上有时可以回避这个编译器限制.
在Godbolt编译器资源管理器上使用你的例子,添加第二个调用者就足以得到gcc6.1 -O2来为你分割函数,所以它可以内联到早期的第二个调用者并进入外部可见的square() (如果没有采用提前返回路径,则以jmp square(int *,int *)[clone .part.3]结束).
code on Godbolt,注意我添加了-std = gnu 14,这是clang编译你的代码所必需的.
void square_inlinewrapper(int* a,int* b) { //if (b - a < 16) return; // gcc inlines this part for us,and calls a private clone of the function! return square(a,b); } # gcc6.1 -O2 (default / generic -march= and -mtune=) mov rax,rsi sub rax,rdi cmp rax,63 jg .L9 rep ret .L9: jmp square(int*,int*) [clone .part.3]
square()本身编译为同一个东西,调用具有大量代码的私有克隆.来自克隆内部的递归调用调用包装器函数,因此在不需要时它们不会执行额外的推/弹工作.
即使在-O3,即使没有其他呼叫者,gcc7也不会这样做.它仍然将其中一个递归调用转换为循环,但另一个只是再次调用大函数.
Clang 3.9和icc17也没有克隆函数,所以你应该手动编写可内联的包装器(如果需要检查,则更改函数的主体以用于递归调用).
以上是大佬教程为你收集整理的c – 早期if语句的函数中不需要的弹出指令全部内容,希望文章能够帮你解决c – 早期if语句的函数中不需要的弹出指令所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。