optabs.h (enum optab_index): Add new OTI_pow and OTI_atan2.
authorRoger Sayle <roger@eyesopen.com>
Tue, 11 Feb 2003 19:34:11 +0000 (19:34 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Tue, 11 Feb 2003 19:34:11 +0000 (19:34 +0000)
* optabs.h (enum optab_index): Add new OTI_pow and OTI_atan2.
(pow_optab, atan2_optab): Define corresponding macros.
* optabs.c (init_optabs): Initialize pow_optab and atan2_optab.
* genopinit.c (optabs): Implement pow_optab and atan2_optab
using pow?f3 and atan2?f3 patterns.
* builtins.c (expand_errno_check): New function to update errno
if necessary, split out from expand_builtin_mathfn.
(expand_builtin_mathfn): Use expand_errno_check.
(expand_builtin_mathfn_2): New function to handle expanding binary
math functions, reusing the code in expand_errno_check.
(expand_builtin): Handle the pow and atan2 math built-ins,
BUILT_IN_{POW,POWF,POWL,ATAN2,ATAN2F,ATAN2L} via the new function
expand_builtin_mathfn_2.

* doc/md.texi: Document new pow?f3 and atan2?f3 patterns.

From-SVN: r62708

gcc/ChangeLog
gcc/builtins.c
gcc/doc/md.texi
gcc/genopinit.c
gcc/optabs.c
gcc/optabs.h

index c5144a9..b162e12 100644 (file)
@@ -1,3 +1,21 @@
+2003-02-11  Roger Sayle  <roger@eyesopen.com>
+
+       * optabs.h (enum optab_index): Add new OTI_pow and OTI_atan2.
+       (pow_optab, atan2_optab): Define corresponding macros.
+       * optabs.c (init_optabs): Initialize pow_optab and atan2_optab.
+       * genopinit.c (optabs): Implement pow_optab and atan2_optab
+       using pow?f3 and atan2?f3 patterns.
+       * builtins.c (expand_errno_check): New function to update errno
+       if necessary, split out from expand_builtin_mathfn.
+       (expand_builtin_mathfn): Use expand_errno_check.
+       (expand_builtin_mathfn_2): New function to handle expanding binary
+       math functions, reusing the code in expand_errno_check.
+       (expand_builtin): Handle the pow and atan2 math built-ins,
+       BUILT_IN_{POW,POWF,POWL,ATAN2,ATAN2F,ATAN2L} via the new function
+       expand_builtin_mathfn_2.
+
+       * doc/md.texi: Document new pow?f3 and atan2?f3 patterns.
+
 Tue Feb 11 19:03:22 MET 2003  Jan Hubicka  <jh@suse.cz>
 
        * combine.c (combine_simplify_rtx): Fix folding of
index e2ad1e8..9478808 100644 (file)
@@ -99,7 +99,9 @@ static rtx expand_builtin_apply               PARAMS ((rtx, rtx, rtx));
 static void expand_builtin_return      PARAMS ((rtx));
 static enum type_class type_to_class   PARAMS ((tree));
 static rtx expand_builtin_classify_type        PARAMS ((tree));
+static void expand_errno_check         PARAMS ((tree, rtx));
 static rtx expand_builtin_mathfn       PARAMS ((tree, rtx, rtx));
+static rtx expand_builtin_mathfn_2     PARAMS ((tree, rtx, rtx));
 static rtx expand_builtin_constant_p   PARAMS ((tree));
 static rtx expand_builtin_args_info    PARAMS ((tree));
 static rtx expand_builtin_next_arg     PARAMS ((tree));
@@ -1655,6 +1657,50 @@ mathfn_built_in (type, fn)
   return implicit_built_in_decls[fcode];
 }
 
+/* If errno must be maintained, expand the RTL to check if the result,
+   TARGET, of a built-in function call, EXP, is NaN, and if so set
+   errno to EDOM.  */
+
+static void
+expand_errno_check (exp, target)
+     tree exp;
+     rtx target;
+{
+  rtx lab;
+
+  if (flag_errno_math && errno_set && HONOR_NANS (GET_MODE (target)))
+    {
+      lab = gen_label_rtx ();
+
+      /* Test the result; if it is NaN, set errno=EDOM because
+        the argument was not in the domain.  */
+      emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
+                              0, lab);
+
+#ifdef TARGET_EDOM
+      {
+#ifdef GEN_ERRNO_RTX
+       rtx errno_rtx = GEN_ERRNO_RTX;
+#else
+       rtx errno_rtx
+         = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
+#endif
+
+       emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
+      }
+#else
+      /* We can't set errno=EDOM directly; let the library call do it.
+        Pop the arguments right away in case the call gets deleted.  */
+      NO_DEFER_POP;
+      expand_call (exp, target, 0);
+      OK_DEFER_POP;
+#endif
+
+      emit_label (lab);
+    }
+}
+
+
 /* Expand a call to one of the builtin math functions (sin, cos, or sqrt).
    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
@@ -1760,41 +1806,105 @@ expand_builtin_mathfn (exp, target, subtarget)
       return 0;
     }
 
-  /* If errno must be maintained, we must set it to EDOM for NaN results.  */
+  expand_errno_check (exp, target);
 
-  if (flag_errno_math && errno_set && HONOR_NANS (argmode))
+  /* Output the entire sequence.  */
+  insns = get_insns ();
+  end_sequence ();
+  emit_insn (insns);
+
+  return target;
+}
+
+/* Expand a call to the builtin binary math functions (pow and atan2).
+   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_mathfn_2 (exp, target, subtarget)
+     tree exp;
+     rtx target, subtarget;
+{
+  optab builtin_optab;
+  rtx op0, op1, insns;
+  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  tree arglist = TREE_OPERAND (exp, 1);
+  tree arg0, arg1;
+  enum machine_mode argmode;
+  bool errno_set = true;
+  bool stable = true;
+
+  if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
+    return 0;
+
+  arg0 = TREE_VALUE (arglist);
+  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+
+  /* Stabilize the arguments.  */
+  if (TREE_CODE (arg0) != VAR_DECL && TREE_CODE (arg0) != PARM_DECL)
+    {
+      arg0 = save_expr (arg0);
+      TREE_VALUE (arglist) = arg0;
+      stable = false;
+    }
+  if (TREE_CODE (arg1) != VAR_DECL && TREE_CODE (arg1) != PARM_DECL)
     {
-      rtx lab1;
+      arg1 = save_expr (arg1);
+      TREE_VALUE (TREE_CHAIN (arglist)) = arg1;
+      stable = false;
+    }
 
-      lab1 = gen_label_rtx ();
+  if (! stable)
+    {
+      exp = copy_node (exp);
+      arglist = tree_cons (NULL_TREE, arg0,
+                          build_tree_list (NULL_TREE, arg1));
+      TREE_OPERAND (exp, 1) = arglist;
+    }
 
-      /* Test the result; if it is NaN, set errno=EDOM because
-        the argument was not in the domain.  */
-      emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
-                              0, lab1);
+  op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
+  op1 = expand_expr (arg1, 0, VOIDmode, 0);
 
-#ifdef TARGET_EDOM
-      {
-#ifdef GEN_ERRNO_RTX
-       rtx errno_rtx = GEN_ERRNO_RTX;
-#else
-       rtx errno_rtx
-         = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
-#endif
+  /* Make a suitable register to place result in.  */
+  target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
 
-       emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
-      }
-#else
-      /* We can't set errno=EDOM directly; let the library call do it.
-        Pop the arguments right away in case the call gets deleted.  */
-      NO_DEFER_POP;
-      expand_call (exp, target, 0);
-      OK_DEFER_POP;
-#endif
+  emit_queue ();
+  start_sequence ();
+
+  switch (DECL_FUNCTION_CODE (fndecl))
+    {
+    case BUILT_IN_POW:
+    case BUILT_IN_POWF:
+    case BUILT_IN_POWL:
+      builtin_optab = pow_optab; break;
+    case BUILT_IN_ATAN2:
+    case BUILT_IN_ATAN2F:
+    case BUILT_IN_ATAN2L:
+      builtin_optab = atan2_optab; break;
+    default:
+      abort ();
+    }
+
+  /* Compute into TARGET.
+     Set TARGET to wherever the result comes back.  */
+  argmode = TYPE_MODE (TREE_TYPE (arg0));
+  target = expand_binop (argmode, builtin_optab, op0, op1,
+                        target, 0, OPTAB_DIRECT);
 
-      emit_label (lab1);
+  /* If we were unable to expand via the builtin, stop the
+     sequence (without outputting the insns) and return 0, causing
+     a call to the library function.  */
+  if (target == 0)
+    {
+      end_sequence ();
+      return 0;
     }
 
+  expand_errno_check (exp, target);
+
   /* Output the entire sequence.  */
   insns = get_insns ();
   end_sequence ();
@@ -4047,6 +4157,19 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        return target;
       break;
 
+    case BUILT_IN_POW:
+    case BUILT_IN_POWF:
+    case BUILT_IN_POWL:
+    case BUILT_IN_ATAN2:
+    case BUILT_IN_ATAN2F:
+    case BUILT_IN_ATAN2L:
+      if (! flag_unsafe_math_optimizations)
+       break;
+      target = expand_builtin_mathfn_2 (exp, target, subtarget);
+      if (target)
+       return target;
+      break;
+
     case BUILT_IN_APPLY_ARGS:
       return expand_builtin_apply_args ();
 
index ce3eb14..da7e38b 100644 (file)
@@ -1,5 +1,5 @@
-@c Copyright (C) 1988, 1989, 1992, 1993, 1994, 1996, 1998, 1999, 2000, 2001, 2002
-@c Free Software Foundation, Inc.
+@c Copyright (C) 1988, 1989, 1992, 1993, 1994, 1996, 1998, 1999, 2000, 2001,
+@c 2002, 2003 Free Software Foundation, Inc.
 @c This is part of the GCC manual.
 @c For copying conditions, see the file gcc.texi.
 
@@ -2607,6 +2607,27 @@ corresponds to the C data type @code{double} and the @code{logf}
 built-in function uses the mode which corresponds to the C data
 type @code{float}.
 
+@cindex @code{pow@var{m}3} instruction pattern
+@item @samp{pow@var{m}3}
+Store the value of operand 1 raised to the exponent operand 2
+into operand 0.
+
+The @code{pow} built-in function of C always uses the mode which
+corresponds to the C data type @code{double} and the @code{powf}
+built-in function uses the mode which corresponds to the C data
+type @code{float}.
+
+@cindex @code{atan2@var{m}3} instruction pattern
+@item @samp{atan2@var{m}3}
+Store the arc tangent (inverse tangent) of operand 1 divided by
+operand 2 into operand 0, using the signs of both arguments to
+determine the quadrant of the result.
+
+The @code{atan2} built-in function of C always uses the mode which
+corresponds to the C data type @code{double} and the @code{atan2f}
+built-in function uses the mode which corresponds to the C data
+type @code{float}.
+
 @cindex @code{floor@var{m}2} instruction pattern
 @item @samp{floor@var{m}2}
 Store the largest integral value not greater than argument.
index 1a0070d..5d996b5 100644 (file)
@@ -1,6 +1,6 @@
 /* Generate code to initialize optabs from machine description.
-   Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -105,6 +105,8 @@ static const char * const optabs[] =
   "smax_optab->handlers[$A].insn_code = CODE_FOR_$(max$F$a3$)",
   "umin_optab->handlers[$A].insn_code = CODE_FOR_$(umin$I$a3$)",
   "umax_optab->handlers[$A].insn_code = CODE_FOR_$(umax$I$a3$)",
+  "pow_optab->handlers[$A].insn_code = CODE_FOR_$(pow$a3$)",
+  "atan2_optab->handlers[$A].insn_code = CODE_FOR_$(atan2$a3$)",
   "neg_optab->handlers[$A].insn_code = CODE_FOR_$(neg$P$a2$)",
   "negv_optab->handlers[(int) $A].insn_code =\n\
     neg_optab->handlers[(int) $A].insn_code = CODE_FOR_$(neg$F$a2$)",
index fbd7bdf..93b1498 100644 (file)
@@ -5512,6 +5512,8 @@ init_optabs ()
   smax_optab = init_optab (SMAX);
   umin_optab = init_optab (UMIN);
   umax_optab = init_optab (UMAX);
+  pow_optab = init_optab (UNKNOWN);
+  atan2_optab = init_optab (UNKNOWN);
 
   /* These three have codes assigned exclusively for the sake of
      have_insn_for.  */
index 5fda4da..e9f95fa 100644 (file)
@@ -1,5 +1,5 @@
 /* Definitions for code generation pass of GNU compiler.
-   Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -108,6 +108,10 @@ enum optab_index
   OTI_umin,
   /* Unsigned maximum value */
   OTI_umax,
+  /* Power */
+  OTI_pow,
+  /* Arc tangent of y/x */
+  OTI_atan2,
 
   /* Move instruction.  */
   OTI_mov,
@@ -202,6 +206,8 @@ extern GTY(()) optab optab_table[OTI_MAX];
 #define smax_optab (optab_table[OTI_smax])
 #define umin_optab (optab_table[OTI_umin])
 #define umax_optab (optab_table[OTI_umax])
+#define pow_optab (optab_table[OTI_pow])
+#define atan2_optab (optab_table[OTI_atan2])
 
 #define mov_optab (optab_table[OTI_mov])
 #define movstrict_optab (optab_table[OTI_movstrict])