http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60971

--- Comment #3 from Jeffrey A. Law <law at redhat dot com> ---
Isn't the real problem here that we emitted the tail call because we thought
the return type from "foo" was close enough to the return type from "bar" that
no coercion was needed?

In the .optimized dump we have:

bar ()
{
  unsigned char _3;
  _Bool _4;

;;   basic block 2, loop depth 0, count 0, freq 10000, maybe hot
;;    prev block 0, next block 1, flags: (NEW, REACHABLE)
;;    pred:       ENTRY [100.0%]  (FALLTHRU,EXECUTABLE)
  _3 = foo (); [tail call]
  _4 = (_Bool) _3;
  return _4;
;;    succ:       EXIT [100.0%]

}

Which is correct AFAICT.

Yet we turn that into:

        jmp     foo     # 5     *sibcall_value  [length = 5]


Which loses the conversion from unsigned char to _Bool which strips off the
bits outside _Bool.

We have the following code which is supposed to handle these kinds of cases,
but obviously isn't sufficient as deals strictly with RTL modes (and at the RTL
mode level, the return types are effectively equivalent)

 /* Check if caller and callee disagree in promotion of function
     return value.  */
  if (try_tail_call)
    {
      enum machine_mode caller_mode, caller_promoted_mode;
      enum machine_mode callee_mode, callee_promoted_mode;
      int caller_unsignedp, callee_unsignedp;
      tree caller_res = DECL_RESULT (current_function_decl);

      caller_unsignedp = TYPE_UNSIGNED (TREE_TYPE (caller_res));
      caller_mode = DECL_MODE (caller_res);
      callee_unsignedp = TYPE_UNSIGNED (TREE_TYPE (funtype));
      callee_mode = TYPE_MODE (TREE_TYPE (funtype));
      caller_promoted_mode
        = promote_function_mode (TREE_TYPE (caller_res), caller_mode,
                                 &caller_unsignedp,
                                 TREE_TYPE (current_function_decl), 1);
      callee_promoted_mode
        = promote_function_mode (TREE_TYPE (funtype), callee_mode,
                                 &callee_unsignedp,
                                 funtype, 1);
      if (caller_mode != VOIDmode
          && (caller_promoted_mode != callee_promoted_mode
              || ((caller_mode != caller_promoted_mode
                   || callee_mode != callee_promoted_mode)
                  && (caller_unsignedp != callee_unsignedp
                      || GET_MODE_BITSIZE (caller_mode)
                         < GET_MODE_BITSIZE (callee_mode)))))
        try_tail_call = 0;
    }


Not surprisingly, if I add "-fno-optimize-sibling-calls" the test passes.

Reply via email to