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