【发布时间】:2011-07-25 13:29:00
【问题描述】:
我最近遇到了很多 gcc 在 x86 上生成非常糟糕的代码的函数。它们都符合以下模式:
if (some_condition) {
/* do something really simple and return */
} else {
/* something complex that needs lots of registers */
}
将简单的情况想象成如此之小,以至于一半或更多的工作都花在了压入和弹出根本不会被修改的寄存器上。如果我手动编写 asm,我会在复杂情况下保存和恢复保存的跨调用寄存器,并在简单情况下完全避免接触堆栈指针。
有什么方法可以让 gcc 变得更聪明一点,并且自己来做这件事吗?最好使用命令行选项,而不是源代码中的丑陋黑客......
编辑:具体来说,这里有一些非常接近我正在处理的一些功能:
if (buf->pos < buf->end) {
return *buf->pos++;
} else {
/* fill buffer */
}
还有一个:
if (!initialized) {
/* complex initialization procedure */
}
return &initialized_object;
还有一个:
if (mutex->type == SIMPLE) {
return atomic_swap(&mutex->lock, 1);
} else {
/* deal with ownership, etc. */
}
编辑 2:我应该首先提到:这些函数不能内联。它们具有外部链接,它们是库代码。允许它们在应用程序中内联会导致各种问题。
【问题讨论】:
-
只是好奇,如果你反转 if 语句会发生什么?
-
无论哪种方式,gcc 都将函数序言/尾声(保存寄存器、调整堆栈对齐等)置于两种情况之外,因此两种情况都会产生成本。
-
您的样本缺少任何复杂的部分。您是否建议即使使用空的 else 块,编译器也会将其弄乱?
-
好的,将
printf("hello, world\n");添加到空块中......说真的,那里有什么并不重要。如果它进行一个或多个函数调用,您将导致堆栈对齐序言,如果它使用大量寄存器,您将导致保存/恢复一个或多个 ebx/esi/edi/ebp。跨度> -
另请注意:我试过
__builtin_expect并没有什么区别。
标签: c gcc code-generation x86