我知道 noreturn 应该用于预期不会将控制权返回给调用者的函数,但我在生成的汇编代码中找不到差异。 有谁知道会生成不同代码的例子吗?
编辑:noreturn 之后不会生成清理代码。
最佳答案
returns_twice
禁用一些 gcc 优化。
例如,在一个旧的 gcc 版本中,我已经准备好了:尾调用优化、全局公共(public)子表达式消除、跳转绕过。
returns_twice
使用 calls_setjmp
机制(围绕源代码树):
if (flags & ECF_RETURNS_TWICE)
cfun->calls_setjmp = true;
tco (gcc/tree-tailcall.c
):
static bool
suitable_for_tail_call_opt_p (void)
{
[...]
/* Any function that calls setjmp might have longjmp called from
any called function. ??? We really should represent this
properly in the CFG so that this needn't be special cased. */
if (cfun->calls_setjmp)
return false;
gcse (gcc/gcse.c
):
static int
gcse_main (rtx f ATTRIBUTE_UNUSED)
{
[...]
/* We do not construct an accurate cfg in functions which call
setjmp, so just punt to be safe. */
if (cfun->calls_setjmp)
return 0;
跳转绕过(gcc/gcse.c
):
static int
bypass_jumps (void)
{
[...]
/* We do not construct an accurate cfg in functions which call
setjmp, so just punt to be safe. */
if (cfun->calls_setjmp)
return 0;
函数既不能是pure也不能是const (gcc/ipa-pure-const.c
):
/* Check the parameters of a function call to CALL_EXPR to see if
there are any references in the parameters that are not allowed for
pure or const functions. Also check to see if this is either an
indirect call, a call outside the compilation unit, or has special
attributes that may also effect the purity. The CALL_EXPR node for
the entire call expression. */
static void
check_call (funct_state local, gimple call)
{
[...]
/* When bad things happen to bad functions, they cannot be const
or pure. */
if (setjmp_call_p (callee_t))
{
local->pure_const_state = IPA_NEITHER;
local->looping = false;
}
函数不能内联(gcc/tree-inline.c
):
/* A callback for walk_gimple_seq to handle statements. Returns
non-NULL iff a function can not be inlined. Also sets the reason
why. */
static tree
inline_forbidden_p_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
struct walk_stmt_info *wip)
{
[...]
/* We cannot inline functions that call setjmp. */
if (setjmp_call_p (t))
{
inline_forbidden_reason
= G_("function %q+F can never be inlined because it uses setjmp");
*handled_ops_p = true;
return t;
}
它还会影响函数栈帧中的寄存器保存区。
示例(总成本):
函数.c:
int func(void)
{
return 0;
}
tco.c:
extern int func(void) /*__attribute__((returns_twice))*/;
int main()
{
return func();
}
不返回两次:
00000000004003a0 <main>:
4003a0: e9 0b 01 00 00 jmpq 4004b0 <func>
4003a5: 90 nop
4003a6: 90 nop
4003a7: 90 nop
返回两次:
00000000004003a0 <main>:
4003a0: 48 83 ec 08 sub $0x8,%rsp
4003a4: e8 17 01 00 00 callq 4004c0 <func>
4003a9: 48 83 c4 08 add $0x8,%rsp
4003ad: c3 retq
4003ae: 90 nop
4003af: 90 nop
关于c - 为有和没有 returns_twice 和 noreturn 的函数生成的汇编器有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18489244/