builtins.c (expand_builtin_int_interclass_roundingfn): New function to handle optabs...
authorUros Bizjak <ubizjak@gmail.com>
Tue, 30 Jan 2007 11:20:07 +0000 (12:20 +0100)
committerUros Bizjak <uros@gcc.gnu.org>
Tue, 30 Jan 2007 11:20:07 +0000 (12:20 +0100)
* builtins.c (expand_builtin_int_interclass_roundingfn): New function
to handle optabs that operate on floating point input argument and
output to integer output.
(expand_builtin_mathfn) [BUILT_IN_ILOGB]: Move from here ...
(expand_builtin_interclass_mathfn) [BUILT_IN_ILOGB]: ... to here.
(expand_builtin): Expand BUILT_IN_ILOGB{,F,L} using
expand_builtin_interclass_mathfn ().
* config/i386/i386.md (fxtractxf3_i387): Rename from *fxtractxf3_i387.
(ilogbsi2): Remove.
(ilogbxf2, ilogb<mode>2): New expanders to implement ilogb, ilogbf and
ilogbl built-in functions as x87 intrinsics.

From-SVN: r121336

gcc/ChangeLog
gcc/builtins.c
gcc/config/i386/i386.md

index 90c826f..cc30009 100644 (file)
@@ -1,3 +1,17 @@
+2007-01-30  Uros Bizjak  <ubizjak@gmail.com>
+
+       * builtins.c (expand_builtin_int_interclass_roundingfn): New function
+       to handle optabs that operate on floating point input argument and
+       output to integer output.
+       (expand_builtin_mathfn) [BUILT_IN_ILOGB]: Move from here ...
+       (expand_builtin_interclass_mathfn) [BUILT_IN_ILOGB]: ... to here.
+       (expand_builtin): Expand BUILT_IN_ILOGB{,F,L} using
+       expand_builtin_interclass_mathfn ().
+       * config/i386/i386.md (fxtractxf3_i387): Rename from *fxtractxf3_i387.
+       (ilogbsi2): Remove.
+       (ilogbxf2, ilogb<mode>2): New expanders to implement ilogb, ilogbf and
+       ilogbl built-in functions as x87 intrinsics.
+
 2007-01-30  Richard Guenther  <rguenther@suse.de>
 
        PR middle-end/27657
index a2f540a..5ba1eae 100644 (file)
@@ -95,6 +95,7 @@ static void expand_errno_check (tree, rtx);
 static rtx expand_builtin_mathfn (tree, rtx, rtx);
 static rtx expand_builtin_mathfn_2 (tree, rtx, rtx);
 static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
+static rtx expand_builtin_interclass_mathfn (tree, rtx, rtx);
 static rtx expand_builtin_sincos (tree);
 static rtx expand_builtin_cexpi (tree, rtx, rtx);
 static rtx expand_builtin_int_roundingfn (tree, rtx, rtx);
@@ -1814,8 +1815,6 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
       errno_set = true; builtin_optab = expm1_optab; break;
     CASE_FLT_FN (BUILT_IN_LOGB):
       errno_set = true; builtin_optab = logb_optab; break;
-    CASE_FLT_FN (BUILT_IN_ILOGB):
-      errno_set = true; builtin_optab = ilogb_optab; break;
     CASE_FLT_FN (BUILT_IN_LOG):
       errno_set = true; builtin_optab = log_optab; break;
     CASE_FLT_FN (BUILT_IN_LOG10):
@@ -2170,6 +2169,86 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
   return target;
 }
 
+/* Expand a call to one of the builtin math functions that operate on
+   floating point argument and output an integer result (ilogb, isinf,
+   isnan, etc).
+   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_interclass_mathfn (tree exp, rtx target, rtx subtarget)
+{
+  optab builtin_optab;
+  enum insn_code icode;
+  rtx op0;
+  tree fndecl = get_callee_fndecl (exp);
+  tree arglist = TREE_OPERAND (exp, 1);
+  enum machine_mode mode;
+  bool errno_set = false;
+  tree arg, narg;
+
+  if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+    return 0;
+
+  arg = TREE_VALUE (arglist);
+
+  switch (DECL_FUNCTION_CODE (fndecl))
+    {
+    CASE_FLT_FN (BUILT_IN_ILOGB):
+      errno_set = true; builtin_optab = ilogb_optab; break;
+    default:
+      gcc_unreachable ();
+    }
+
+  /* There's no easy way to detect the case we need to set EDOM.  */
+  if (flag_errno_math && errno_set)
+    return NULL_RTX;
+
+  /* Optab mode depends on the mode of the input argument.  */
+  mode = TYPE_MODE (TREE_TYPE (arg));
+
+  icode = builtin_optab->handlers[(int) mode].insn_code;
+  /* Before working hard, check whether the instruction is available.  */
+  if (icode != CODE_FOR_nothing)
+    {
+      /* Make a suitable register to place result in.  */
+      if (!target
+         || GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
+         target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
+
+      gcc_assert (insn_data[icode].operand[0].predicate
+                 (target, GET_MODE (target)));
+
+      /* 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);
+
+      if (mode != GET_MODE (op0))
+       op0 = convert_to_mode (mode, op0, 0);
+
+      /* Compute into TARGET.
+        Set TARGET to wherever the result comes back.  */
+      emit_unop_insn (icode, target, op0, UNKNOWN);
+      return target;
+    }
+
+  target = expand_call (exp, target, target == const0_rtx);
+
+  return target;
+}
+
 /* Expand a call to the builtin sincos math function.
    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
@@ -5817,7 +5896,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     CASE_FLT_FN (BUILT_IN_EXP2):
     CASE_FLT_FN (BUILT_IN_EXPM1):
     CASE_FLT_FN (BUILT_IN_LOGB):
-    CASE_FLT_FN (BUILT_IN_ILOGB):
     CASE_FLT_FN (BUILT_IN_LOG):
     CASE_FLT_FN (BUILT_IN_LOG10):
     CASE_FLT_FN (BUILT_IN_LOG2):
@@ -5842,6 +5920,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
+    CASE_FLT_FN (BUILT_IN_ILOGB):
+      if (! flag_unsafe_math_optimizations)
+       break;
+      target = expand_builtin_interclass_mathfn (exp, target, subtarget);
+      if (target)
+       return target;
+      break;
+
     CASE_FLT_FN (BUILT_IN_LCEIL):
     CASE_FLT_FN (BUILT_IN_LLCEIL):
     CASE_FLT_FN (BUILT_IN_LFLOOR):
index 21d1c2b..a9620e2 100644 (file)
   DONE;
 })
 
-(define_insn "*fxtractxf3_i387"
+(define_insn "fxtractxf3_i387"
   [(set (match_operand:XF 0 "register_operand" "=f")
        (unspec:XF [(match_operand:XF 2 "register_operand" "0")]
                   UNSPEC_XTRACT_FRACT))
   DONE;
 })
 
-(define_expand "ilogbsi2"
-  [(parallel [(set (match_dup 2)
-                  (unspec:XF [(match_operand:XF 1 "register_operand" "")]
-                             UNSPEC_XTRACT_FRACT))
-             (set (match_dup 3)
-                  (unspec:XF [(match_dup 1)] UNSPEC_XTRACT_EXP))])
-   (parallel [(set (match_operand:SI 0 "register_operand" "")
-                  (fix:SI (match_dup 3)))
-             (clobber (reg:CC FLAGS_REG))])]
+(define_expand "ilogbxf2"
+  [(use (match_operand:SI 0 "register_operand" ""))
+   (use (match_operand:XF 1 "register_operand" ""))]
   "TARGET_USE_FANCY_MATH_387
-   && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387)
    && flag_unsafe_math_optimizations && !optimize_size"
 {
-  operands[2] = gen_reg_rtx (XFmode);
-  operands[3] = gen_reg_rtx (XFmode);
+  rtx op0 = gen_reg_rtx (XFmode);
+  rtx op1 = gen_reg_rtx (XFmode);
+
+  emit_insn (gen_fxtractxf3_i387 (op0, op1, operands[1]));
+  emit_insn (gen_fix_truncxfsi2 (operands[0], op1));
+  DONE;
+})
+
+(define_expand "ilogb<mode>2"
+  [(use (match_operand:SI 0 "register_operand" ""))
+   (use (match_operand:X87MODEF12 1 "register_operand" ""))]
+  "TARGET_USE_FANCY_MATH_387
+   && (!(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
+       || TARGET_MIX_SSE_I387)
+   && flag_unsafe_math_optimizations && !optimize_size"
+{
+  rtx op0 = gen_reg_rtx (XFmode);
+  rtx op1 = gen_reg_rtx (XFmode);
+
+  emit_insn (gen_fxtract_extend<mode>xf3_i387 (op0, op1, operands[1]));
+  emit_insn (gen_fix_truncxfsi2 (operands[0], op1));
+  DONE;
 })
 
 (define_insn "*f2xm1xf2_i387"