Search code examples
cassemblynoreturn

What is the difference between assembler generated for functions with and without returns_twice and noreturn?


I understand that noreturn should be used for functions which are expected to doesn't return control to the caller, but I can't find difference in generated assembler codes. Does anyone know examples which will generate different codes?

Edit: The noreturn does not generate cleanup code after it.


Solution

  • returns_twice disables some gcc optimizations.

    As an example, in an old gcc version I have laying around: tail call optimization, global common subexpression elimination, jump bypassing.

    returns_twice uses calls_setjmp machinery (all around the source tree):

              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;
    

    jump-bypassing (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;
    

    The function can be neither pure nor 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;
            }
    

    The function cannot be inlined (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;
            }
    

    It also affects the register save area in the function's stack frame.

    Example(tco):

    func.c:

    int func(void)
    {
            return 0;
    }
    

    tco.c:

    extern int func(void)  /*__attribute__((returns_twice))*/;
    
    int main()
    {
            return func();
    }
    

    doesn't return twice:

    00000000004003a0 <main>:
      4003a0:       e9 0b 01 00 00          jmpq   4004b0 <func>
      4003a5:       90                      nop
      4003a6:       90                      nop
      4003a7:       90                      nop
    

    returns twice:

    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