builtins.c (expand_builtin_int_roundingfn_2): New function.
authorRichard Guenther <rguenther@suse.de>
Sat, 21 Oct 2006 19:55:07 +0000 (19:55 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Sat, 21 Oct 2006 19:55:07 +0000 (19:55 +0000)
2006-10-21  Richard Guenther  <rguenther@suse.de>

* builtins.c (expand_builtin_int_roundingfn_2): New function.
(expand_builtin): Use it to expand lrint instead of
expand_builtin_mathfn.

From-SVN: r117936

gcc/ChangeLog
gcc/builtins.c

index 8d33188..42b4ded 100644 (file)
@@ -1,3 +1,9 @@
+2006-10-21  Richard Guenther  <rguenther@suse.de>
+
+       * builtins.c (expand_builtin_int_roundingfn_2): New function.
+       (expand_builtin): Use it to expand lrint instead of
+       expand_builtin_mathfn.
+
 2006-10-21  Uros Bizjak  <uros@kss-loka.si>
 
        PR target/19398
index 711cf41..c1996dc 100644 (file)
@@ -95,6 +95,7 @@ static rtx expand_builtin_mathfn_2 (tree, rtx, rtx);
 static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
 static rtx expand_builtin_sincos (tree);
 static rtx expand_builtin_int_roundingfn (tree, rtx, rtx);
+static rtx expand_builtin_int_roundingfn_2 (tree, rtx, rtx);
 static rtx expand_builtin_args_info (tree);
 static rtx expand_builtin_next_arg (void);
 static rtx expand_builtin_va_start (tree);
@@ -1835,9 +1836,6 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
       builtin_optab = nearbyint_optab; break;
     CASE_FLT_FN (BUILT_IN_RINT):
       builtin_optab = rint_optab; break;
-    CASE_FLT_FN (BUILT_IN_LRINT):
-    CASE_FLT_FN (BUILT_IN_LLRINT):
-      builtin_optab = lrint_optab; break;
     default:
       gcc_unreachable ();
     }
@@ -2210,7 +2208,9 @@ expand_builtin_sincos (tree exp)
   return const0_rtx;
 }
 
-/* Expand a call to one of the builtin rounding functions (lfloor).
+/* Expand a call to one of the builtin rounding functions gcc defines
+   as an extension (lfloor and lceil).  As these are gcc extensions we
+   do not need to worry about setting errno to EDOM.
    If expanding via optab fails, lower expression to (int)(floor(x)).
    EXP is the expression that is a call to the builtin function;
    if convenient, the result should be placed in TARGET.  SUBTARGET may
@@ -2309,6 +2309,88 @@ expand_builtin_int_roundingfn (tree exp, rtx target, rtx subtarget)
   return target;
 }
 
+/* Expand a call to one of the builtin math functions doing integer
+   conversion (lrint).
+   Return 0 if a normal call should be emitted rather than expanding the
+   function in-line.  EXP is the expression that is a call to the builtin
+   function; if convenient, the result should be placed in TARGET.
+   SUBTARGET may be used as the target for computing one of EXP's operands.  */
+
+static rtx
+expand_builtin_int_roundingfn_2 (tree exp, rtx target, rtx subtarget)
+{
+  optab builtin_optab;
+  rtx op0, insns;
+  tree fndecl = get_callee_fndecl (exp);
+  tree arglist = TREE_OPERAND (exp, 1);
+  enum machine_mode mode;
+  tree arg, narg;
+
+  /* There's no easy way to detect the case we need to set EDOM.  */
+  if (flag_errno_math)
+    return NULL_RTX;
+
+  if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+    return NULL_RTX;
+
+  arg = TREE_VALUE (arglist);
+
+  switch (DECL_FUNCTION_CODE (fndecl))
+    {
+    CASE_FLT_FN (BUILT_IN_LRINT):
+    CASE_FLT_FN (BUILT_IN_LLRINT):
+      builtin_optab = lrint_optab; break;
+    default:
+      gcc_unreachable ();
+    }
+
+  /* Make a suitable register to place result in.  */
+  mode = TYPE_MODE (TREE_TYPE (exp));
+
+  /* Before working hard, check whether the instruction is available.  */
+  if (builtin_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+    {
+      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.  */
+      narg = builtin_save_expr (arg);
+      if (narg != arg)
+       {
+         arg = narg;
+         arglist = build_tree_list (NULL_TREE, arg);
+         exp = build_function_call_expr (fndecl, arglist);
+       }
+
+      op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+
+      start_sequence ();
+
+      /* Compute into TARGET.
+        Set TARGET to wherever the result comes back.  */
+      target = expand_unop (mode, builtin_optab, op0, target, 0);
+
+      if (target != 0)
+       {
+         /* 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 ();
+    }
+
+  target = expand_call (exp, target, target == const0_rtx);
+
+  return target;
+}
+
 /* To evaluate powi(x,n), the floating point value x raised to the
    constant integer exponent n, we use a hybrid algorithm that
    combines the "window method" with look-up tables.  For an
@@ -5718,8 +5800,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     CASE_FLT_FN (BUILT_IN_ROUND):
     CASE_FLT_FN (BUILT_IN_NEARBYINT):
     CASE_FLT_FN (BUILT_IN_RINT):
-    CASE_FLT_FN (BUILT_IN_LRINT):
-    CASE_FLT_FN (BUILT_IN_LLRINT):
       target = expand_builtin_mathfn (exp, target, subtarget);
       if (target)
        return target;
@@ -5734,6 +5814,13 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
+    CASE_FLT_FN (BUILT_IN_LRINT):
+    CASE_FLT_FN (BUILT_IN_LLRINT):
+      target = expand_builtin_int_roundingfn_2 (exp, target, subtarget);
+      if (target)
+       return target;
+      break;
+
     CASE_FLT_FN (BUILT_IN_POW):
       target = expand_builtin_pow (exp, target, subtarget);
       if (target)