函数中不必要的弹出指令,前面有if语句
Unneccessary pop instructions in functions with early if statement
在摆弄godbolt.org时,我注意到gcc(6.2, 7.0快照),clang(3.9)和icc(17)在编译接近
的东西时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编译为:
mov rax, rcx
sub rax, rdx
cmp rax, 7
jg .L74
not DWORD PTR [rdx]
ret
.L74:
这使我相信没有任何代码阻止编译器发出这段较短的代码。
编译器这样做是有原因的吗?有没有一种方法可以让它们编译成更短的版本而不需要编译大小?
这里有一个关于Godbolt的例子,它再现了这个。这似乎与复杂部分递归有关
这是一个已知的编译器限制,请参阅我对该问题的评论。IDK为什么存在;也许对于编译器来说,当它们还没有完成保存regs时,很难决定它们可以在不溢出的情况下做些什么。
将提前取出的签入包装器中,当它足够小而可以内联时,通常是有用的。
看起来现代的gcc有时可以绕过这个编译器的限制。
在Godbolt编译器资源管理器上使用您的示例,添加第二个调用者足以让gcc6.1 -O2为您拆分函数,因此它可以将早期输出内联到第二个调用者和外部可见的square()
(如果不采用早期输出返回路径,则以jmp square(int*, int*) [clone .part.3]
结束)。
代码,注意我添加了-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()
本身编译为相同的东西,调用具有大量代码的私有克隆。来自克隆内部的递归调用调用包装器函数,因此它们不会在不需要时执行额外的push/pop工作。
即使gcc7在没有其他调用者时也不会这样做,即使是在-O3。它仍然将其中一个递归调用转换为循环,但另一个只是再次调用大函数。
Clang 3.9和icc17也不克隆函数,因此您应该手动编写可内联的包装器(并更改函数的主体以将其用于递归调用,如果那里需要检查的话)。
您可能希望将包装器命名为square
,并将主体重命名为私有名称(如static void square_impl
)。
- 我的简单if-else语句是如何无法访问的代码
- 如何将enable-if与模板参数和参数包一起使用
- 无论条件是否为true,if总是在c++中执行
- Arduino:for/while/if在void setup()或void loop()之前?——错误:之前需要不合格
- Insert函数不适用于2 if语句C++
- If语句未被求值C++
- C++嵌套if语句,基本货币交换
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- 是否可以使用if constexpr删除控制流语句
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- 如何删除peer if else分支中的冗长句子
- 我似乎对if/else的基本语句有问题:/
- if数组上的随机数
- 如何在C++向量中奇数元素前面加上值-1,我在使用insert函数时遇到了问题
- 将按位if条件转换为普通if条件
- If语句在c++中被忽略
- 比较if语句中的数组值和int值
- 使用if-else将数字转换为单词
- if 语句仅在前面有调试 cout 行(C 中的多线程)时才通过
- 函数中不必要的弹出指令,前面有if语句