On Thu, Mar 15, 2012 at 2:06 PM, Jakub Jelinek <ja...@redhat.com> wrote:
> Hi!
>
> If __builtin_ir{int,ound}{,f,l} expansion through optab fails,
> we would end up generating a call to __builtin_ir{int,ound}{,f,l}
> function (there is no ir{int,ound}{,f,l} in libm), which is wrong,
> we should expand it as (int) lr{int,ound}{,f,l} in that case (similarly
> to what we already do with __builtin_{i,l,ll}{ceil,floor}{,f,l}).
>
> This has been reported as a failure to build mplayer on x86_64-linux
> as well as a failure to build pulseaudio on s390x-linux.
>
> Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux,
> ok for trunk and 4.7.0?

Yes.

Thanks,
Richard.

> 2012-03-15  Jakub Jelinek  <ja...@redhat.com>
>            Andrew Pinski  <apin...@cavium.com>
>
>        PR middle-end/52592
>        * builtins.c (expand_builtin_int_roundingfn_2): If expanding
>        BUILT_IN_IR{INT,OUND}* using optab fails, emit lr{int,ound}*
>        calls instead of __builtin_ir{int,ound}*.
>
>        * gcc.dg/pr52592.c: New test.
>
> --- gcc/builtins.c.jj   2012-02-12 15:46:32.000000000 +0100
> +++ gcc/builtins.c      2012-03-15 10:20:59.335215596 +0100
> @@ -2841,10 +2841,7 @@ expand_builtin_int_roundingfn_2 (tree ex
>   tree fndecl = get_callee_fndecl (exp);
>   tree arg;
>   enum machine_mode mode;
> -
> -  /* There's no easy way to detect the case we need to set EDOM.  */
> -  if (flag_errno_math)
> -    return NULL_RTX;
> +  enum built_in_function fallback_fn = BUILT_IN_NONE;
>
>   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
>      gcc_unreachable ();
> @@ -2854,47 +2851,79 @@ expand_builtin_int_roundingfn_2 (tree ex
>   switch (DECL_FUNCTION_CODE (fndecl))
>     {
>     CASE_FLT_FN (BUILT_IN_IRINT):
> +      fallback_fn = BUILT_IN_LRINT;
> +      /* FALLTHRU */
>     CASE_FLT_FN (BUILT_IN_LRINT):
>     CASE_FLT_FN (BUILT_IN_LLRINT):
> -      builtin_optab = lrint_optab; break;
> +      builtin_optab = lrint_optab;
> +      break;
>
>     CASE_FLT_FN (BUILT_IN_IROUND):
> +      fallback_fn = BUILT_IN_LROUND;
> +      /* FALLTHRU */
>     CASE_FLT_FN (BUILT_IN_LROUND):
>     CASE_FLT_FN (BUILT_IN_LLROUND):
> -      builtin_optab = lround_optab; break;
> +      builtin_optab = lround_optab;
> +      break;
>
>     default:
>       gcc_unreachable ();
>     }
>
> +  /* There's no easy way to detect the case we need to set EDOM.  */
> +  if (flag_errno_math && fallback_fn == BUILT_IN_NONE)
> +    return NULL_RTX;
> +
>   /* Make a suitable register to place result in.  */
>   mode = TYPE_MODE (TREE_TYPE (exp));
>
> -  target = gen_reg_rtx (mode);
> +  /* There's no easy way to detect the case we need to set EDOM.  */
> +  if (!flag_errno_math)
> +    {
> +      target = gen_reg_rtx (mode);
>
> -  /* Wrap the computation of the argument in a SAVE_EXPR, as we may
> -     need to expand the argument again.  This way, we will not perform
> -     side-effects more the once.  */
> -  CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
> +      /* Wrap the computation of the argument in a SAVE_EXPR, as we may
> +        need to expand the argument again.  This way, we will not perform
> +        side-effects more the once.  */
> +      CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
> +
> +      op0 = expand_expr (arg, NULL, VOIDmode, EXPAND_NORMAL);
> +
> +      start_sequence ();
> +
> +      if (expand_sfix_optab (target, op0, builtin_optab))
> +       {
> +         /* Output the entire sequence.  */
> +         insns = get_insns ();
> +         end_sequence ();
> +         emit_insn (insns);
> +         return target;
> +       }
> +
> +      /* If we were unable to expand via the builtin, stop the sequence
> +        (without outputting the insns) and call to the library function
> +        with the stabilized argument list.  */
> +      end_sequence ();
> +    }
>
> -  op0 = expand_expr (arg, NULL, VOIDmode, EXPAND_NORMAL);
> +  if (fallback_fn != BUILT_IN_NONE)
> +    {
> +      /* Fall back to rounding to long int.  Use implicit_p 0 - for non-C99
> +        targets, (int) round (x) should never be transformed into
> +        BUILT_IN_IROUND and if __builtin_iround is called directly, emit
> +        a call to lround in the hope that the target provides at least some
> +        C99 functions.  This should result in the best user experience for
> +        not full C99 targets.  */
> +      tree fallback_fndecl = mathfn_built_in_1 (TREE_TYPE (arg),
> +                                               fallback_fn, 0);
>
> -  start_sequence ();
> +      exp = build_call_nofold_loc (EXPR_LOCATION (exp),
> +                                  fallback_fndecl, 1, arg);
>
> -  if (expand_sfix_optab (target, op0, builtin_optab))
> -    {
> -      /* Output the entire sequence.  */
> -      insns = get_insns ();
> -      end_sequence ();
> -      emit_insn (insns);
> -      return target;
> +      target = expand_call (exp, NULL_RTX, target == const0_rtx);
> +      return convert_to_mode (mode, target, 0);
>     }
>
> -  /* If we were unable to expand via the builtin, stop the sequence
> -     (without outputting the insns) and call to the library function
> -     with the stabilized argument list.  */
> -  end_sequence ();
> -
>   target = expand_call (exp, target, target == const0_rtx);
>
>   return target;
> --- gcc/testsuite/gcc.dg/pr52592.c.jj   2012-03-15 10:23:51.701213103 +0100
> +++ gcc/testsuite/gcc.dg/pr52592.c      2012-03-15 10:20:18.000000000 +0100
> @@ -0,0 +1,21 @@
> +/* PR middle-end/52592 */
> +/* { dg-do compile } */
> +/* { dg-options "-std=gnu99 -O2 -ffast-math" } */
> +
> +#define T(type, name) \
> +type name (type);              \
> +__attribute__((cold))          \
> +int f##name (type x)           \
> +{                              \
> +  return (int) name (x);       \
> +}
> +
> +T (double, round)
> +T (float, roundf)
> +T (long double, roundl)
> +T (double, rint)
> +T (float, rintf)
> +T (long double, rintl)
> +
> +/* { dg-final { scan-assembler-not "__builtin_iround" } } */
> +/* { dg-final { scan-assembler-not "__builtin_irint" } } */
>
>        Jakub

Reply via email to