[PATCH] Fix __builtin_ir{ound,int}{,f,l} expansion (PR middle-end/52592)

2012-03-15 Thread Jakub Jelinek
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?

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.0 +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;
--- 

Re: [PATCH] Fix __builtin_ir{ound,int}{,f,l} expansion (PR middle-end/52592)

2012-03-15 Thread Richard Guenther
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.0 +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