0

呼び出し元に制御を返さないことが期待される関数には noreturn を使用する必要があることは理解していますが、生成されたアセンブラー コードに違いが見つかりません。異なるコードを生成する例を知っている人はいますか?

編集: noreturn はその後、クリーンアップ コードを生成しません。

4

1 に答える 1

2

returns_twice一部の gcc 最適化を無効にします。

例として、古い gcc バージョンでは、テール コールの最適化、グローバルな共通部分式の削除、ジャンプ バイパスなどを配置しています。

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;

関数は純粋でも 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;
        }

また、関数のスタック フレーム内のレジスタ保存領域にも影響します。

例 (tco):

func.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

2回返します:

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
于 2013-08-30T12:33:06.143 に答える