re PR middle-end/19402 (__builtin_powi? still missing)
authorRichard Guenther <rguenth@gcc.gnu.org>
Wed, 9 Feb 2005 20:58:13 +0000 (20:58 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Wed, 9 Feb 2005 20:58:13 +0000 (20:58 +0000)
2005-02-09  Richard Guenther  <rguenth@gcc.gnu.org>

PR middle-end/19402

* builtins.def: New __builtin_powi[lf].
* builtins.c (mathfn_built_in): Handle BUILT_IN_POWI.
(expand_builtin_powi): New function.
(expand_builtin): Dispatch to expand_builtin_powi.
* libgcc2.h: Add prototypes for __builtin_powi[lf].
* libgcc2.c: Add __builtin_powi[lf] implementation.
* mklibgcc.in: Add __builtin_powi[lf] to lib2funcs.
* optabs.h: Add powi_optab.
* optabs.c (init_optabs): Initialize powi_optab.
* doc/extend.texi: Document __builtin_powi[lf].

* gcc.dg/pr19402-1.c: New testcase.
* gcc.dg/pr19402-2.c: likewise.

From-SVN: r94774

13 files changed:
gcc/ChangeLog
gcc/builtins.c
gcc/builtins.def
gcc/doc/extend.texi
gcc/libgcc-std.ver
gcc/libgcc2.c
gcc/libgcc2.h
gcc/mklibgcc.in
gcc/optabs.c
gcc/optabs.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr19402-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr19402-2.c [new file with mode: 0644]

index 20bc95669ff4bfefb289ec431418a855726f4214..60107b013c33c94f61728b3e62a623d4db618a04 100644 (file)
@@ -1,3 +1,17 @@
+2005-02-09  Richard Guenther  <rguenth@gcc.gnu.org>
+
+       PR middle-end/19402
+       * builtins.def: New __builtin_powi[lf].
+       * builtins.c (mathfn_built_in): Handle BUILT_IN_POWI.
+       (expand_builtin_powi): New function.
+       (expand_builtin): Dispatch to expand_builtin_powi.
+       * libgcc2.h: Add prototypes for __builtin_powi[lf].
+       * libgcc2.c: Add __builtin_powi[lf] implementation.
+       * mklibgcc.in: Add __builtin_powi[lf] to lib2funcs.
+       * optabs.h: Add powi_optab.
+       * optabs.c (init_optabs): Initialize powi_optab.
+       * doc/extend.texi: Document __builtin_powi[lf].
+
 2005-02-09  Dorit Naishlos  <dorit@il.ibm.com>
 
        * tree-vectorizer.c (vect_set_dump_settings): Check that dump_file 
index 09c5b6b795e7e8e1083b0a6adcd88c4640741bca..36316156c5f340a303babf54e1f9733812d1f35a 100644 (file)
@@ -1563,6 +1563,7 @@ mathfn_built_in (tree type, enum built_in_function fn)
       CASE_MATHFN (BUILT_IN_NEXTAFTER)
       CASE_MATHFN (BUILT_IN_NEXTTOWARD)
       CASE_MATHFN (BUILT_IN_POW)
+      CASE_MATHFN (BUILT_IN_POWI)
       CASE_MATHFN (BUILT_IN_POW10)
       CASE_MATHFN (BUILT_IN_REMAINDER)
       CASE_MATHFN (BUILT_IN_REMQUO)
@@ -2349,6 +2350,66 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
   return expand_builtin_mathfn_2 (exp, target, subtarget);
 }
 
+/* Expand a call to the powi built-in mathematical 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
+   function; if convenient, the result should be placed in TARGET.  */
+
+static rtx
+expand_builtin_powi (tree exp, rtx target, rtx subtarget)
+{
+  tree arglist = TREE_OPERAND (exp, 1);
+  tree arg0, arg1;
+  rtx op0, op1;
+  enum machine_mode mode;
+
+  if (! validate_arglist (arglist, REAL_TYPE, INTEGER_TYPE, VOID_TYPE))
+    return 0;
+
+  arg0 = TREE_VALUE (arglist);
+  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+  mode = TYPE_MODE (TREE_TYPE (exp));
+
+  /* Handle constant power.  */
+
+  if (TREE_CODE (arg1) == INTEGER_CST
+      && ! TREE_CONSTANT_OVERFLOW (arg1))
+    {
+      HOST_WIDE_INT n = TREE_INT_CST_LOW (arg1);
+
+      /* If the exponent is -1, 0, 1 or 2, then expand_powi is exact.
+        Otherwise, check the number of multiplications required.  */
+      if ((TREE_INT_CST_HIGH (arg1) == 0
+          || TREE_INT_CST_HIGH (arg1) == -1)
+         && ((n >= -1 && n <= 2)
+             || (! optimize_size
+                 && powi_cost (n) <= POWI_MAX_MULTS)))
+       {
+         op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
+         op0 = force_reg (mode, op0);
+         return expand_powi (op0, mode, n);
+       }
+    }
+
+  /* Emit a libcall to libgcc.  */
+
+  if (target == NULL_RTX)
+    target = gen_reg_rtx (mode);
+
+  op0 = expand_expr (arg0, subtarget, mode, 0);
+  if (GET_MODE (op0) != mode)
+    op0 = convert_to_mode (mode, op0, 0);
+  op1 = expand_expr (arg1, 0, word_mode, 0);
+  if (GET_MODE (op1) != word_mode)
+    op1 = convert_to_mode (word_mode, op1, 0);
+
+  target = emit_library_call_value (powi_optab->handlers[(int) mode].libfunc,
+                                   target, LCT_CONST_MAKE_BLOCK, mode, 2,
+                                   op0, mode, op1, word_mode);
+
+  return target;
+}
+
 /* Expand expression EXP which is a call to the strlen builtin.  Return 0
    if we failed the caller should emit a normal call, otherwise
    try to get the result in TARGET, if convenient.  */
@@ -5186,6 +5247,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
+    case BUILT_IN_POWI:
+    case BUILT_IN_POWIF:
+    case BUILT_IN_POWIL:
+      target = expand_builtin_powi (exp, target, subtarget);
+      if (target)
+       return target;
+      break;
+
     case BUILT_IN_ATAN2:
     case BUILT_IN_ATAN2F:
     case BUILT_IN_ATAN2L:
index 9fc347f7369851dc2061eb64590768836396dca7..972b6a2ee83da25520650b82457fa725d02f73c7 100644 (file)
@@ -306,6 +306,9 @@ DEF_EXT_LIB_BUILTIN    (BUILT_IN_POW10, "pow10", BT_FN_DOUBLE_DOUBLE, ATTR_MATHF
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_POW10F, "pow10f", BT_FN_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_POW10L, "pow10l", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_C90RES_BUILTIN (BUILT_IN_POWF, "powf", BT_FN_FLOAT_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)
+DEF_GCC_BUILTIN        (BUILT_IN_POWI, "powi", BT_FN_DOUBLE_DOUBLE_INT, ATTR_MATHFN_FPROUNDING)
+DEF_GCC_BUILTIN        (BUILT_IN_POWIF, "powif", BT_FN_FLOAT_FLOAT_INT, ATTR_MATHFN_FPROUNDING)
+DEF_GCC_BUILTIN        (BUILT_IN_POWIL, "powil", BT_FN_LONGDOUBLE_LONGDOUBLE_INT, ATTR_MATHFN_FPROUNDING)
 DEF_C99_C90RES_BUILTIN (BUILT_IN_POWL, "powl", BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_REMAINDER, "remainder", BT_FN_DOUBLE_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_REMAINDERF, "remainderf", BT_FN_FLOAT_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)
index e730511c212c5f2123ef74b170ef4c2afe45c404..7e4d66aaa8709f5e2f2543937389c281308aea06 100644 (file)
@@ -4507,6 +4507,9 @@ identifier, or a sequence of member accesses and array references.
 @findex __builtin_islessequal
 @findex __builtin_islessgreater
 @findex __builtin_isunordered
+@findex __builtin_powi
+@findex __builtin_powif
+@findex __builtin_powil
 @findex _Exit
 @findex _exit
 @findex abort
@@ -5368,6 +5371,21 @@ Similar to @code{__builtin_parity}, except the argument type is
 @code{unsigned long long}.
 @end deftypefn
 
+@deftypefn {Built-in Function} double __builtin_powi (double, int)
+Returns the first argument raised to the power of the second.  Unlike the
+@code{pow} function no guarantees about precision and rounding are made.
+@end deftypefn
+
+@deftypefn {Built-in Function} float __builtin_powif (float, int)
+Similar to @code{__builtin_powi}, except the argument and return types
+are @code{float}.
+@end deftypefn
+
+@deftypefn {Built-in Function} {long double} __builtin_powil (long double, int)
+Similar to @code{__builtin_powi}, except the argument and return types
+are @code{long double}.
+@end deftypefn
+
 
 @node Target Builtins
 @section Built-in Functions Specific to Particular Target Machines
index db68ea6ef94ef96f0c51403e876e2057b0e40fbd..b701fcf95339291e7e843f736a8f654e4fbde688 100644 (file)
@@ -233,3 +233,12 @@ GCC_3.4.4 {
   __negvti2
   __subvti3
 }
+
+%inherit GCC_4.0.0 GCC_3.4.4
+GCC_4.0.0 {
+  # libgcc2 __builtin_powi helpers.
+  __powisf2
+  __powidf2
+  __powixf2
+  __powitf2
+}
\ No newline at end of file
index 1b1455d5d8d785870a71c8ccd621dc9ff8d8cbef..2d47c0d7f649c875fd491cb8b8032d741bb34d1d 100644 (file)
@@ -1463,6 +1463,42 @@ __fixunssfSI (SFtype a)
     return (Wtype) (a + Wtype_MIN) - Wtype_MIN;
   return (Wtype) a;
 }
+#endif
+\f
+/* Integer power helper used from __builtin_powi for non-constant
+   exponents.  */
+
+#if defined(L_powisf2) || defined(L_powidf2) \
+    || (defined(L_powixf2) && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 80) \
+    || (defined(L_powitf2) && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
+# if defined(L_powisf2)
+#  define TYPE SFtype
+#  define NAME __powisf2
+# elif defined(L_powidf2)
+#  define TYPE DFtype
+#  define NAME __powidf2
+# elif defined(L_powixf2)
+#  define TYPE XFtype
+#  define NAME __powixf2
+# elif defined(L_powitf2)
+#  define TYPE TFtype
+#  define NAME __powitf2
+# endif
+
+TYPE
+NAME (TYPE x, Wtype m)
+{
+  UWtype n = m < 0 ? -m : m;
+  TYPE y = n % 2 ? x : 1;
+  while (n >>= 1)
+    {
+      x = x * x;
+      if (n % 2)
+       y = y * x;
+    }
+  return m < 0 ? 1/y : y;
+}
+
 #endif
 \f
 /* From here on down, the routines use normal data types.  */
index f6b8fa43aef382957c813851b2b5d46c5627fbb7..025dd6f5aefa9b8f1e2360a498da73cf2fa3e429 100644 (file)
@@ -305,18 +305,22 @@ extern UWtype __fixunsdfSI (DFtype);
 extern UWtype __fixunssfSI (SFtype);
 extern DWtype __fixunsdfDI (DFtype);
 extern DWtype __fixunssfDI (SFtype);
+extern SFtype __powisf2 (SFtype, Wtype);
+extern DFtype __powidf2 (DFtype, Wtype);
 
 #if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 80
 extern DWtype __fixxfdi (XFtype);
 extern DWtype __fixunsxfDI (XFtype);
 extern XFtype __floatdixf (DWtype);
 extern UWtype __fixunsxfSI (XFtype);
+extern XFtype __powixf2 (XFtype, Wtype);
 #endif
 
 #if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128
 extern DWtype __fixunstfDI (TFtype);
 extern DWtype __fixtfdi (TFtype);
 extern TFtype __floatditf (DWtype);
+extern TFtype __powitf2 (TFtype, Wtype);
 #endif
 #endif /* BITS_PER_UNIT == 8 */
 
index 3cdd4bb96e74c889fcc77b6aea9e73054f71bff6..7ac1dbf24de0ad03f38e53eb16314ee9a9a2dee1 100644 (file)
@@ -61,7 +61,8 @@ lib2funcs='_muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3
        _enable_execute_stack _trampoline __main _absvsi2 _absvdi2 _addvsi3
        _addvdi3 _subvsi3 _subvdi3 _mulvsi3 _mulvdi3 _negvsi2 _negvdi2 _ctors
        _ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab
-       _popcountsi2 _popcountdi2 _paritysi2 _paritydi2'
+       _popcountsi2 _popcountdi2 _paritysi2 _paritydi2 _powisf2 _powidf2
+       _powixf2 _powitf2'
 
 # Disable SHLIB_LINK if shared libgcc not enabled.
 if [ "@enable_shared@" = "no" ]; then
index 889f9156dd165027a6d7954a0cffd5a02799dcaf..75c78cd9b2d83c7533efb213ecdfb9f0a1449933 100644 (file)
@@ -5049,6 +5049,8 @@ init_optabs (void)
   vec_realign_load_optab = init_optab (UNKNOWN);
   movmisalign_optab = init_optab (UNKNOWN);
 
+  powi_optab = init_optab (UNKNOWN);
+
   /* Conversions.  */
   sext_optab = init_convert_optab (SIGN_EXTEND);
   zext_optab = init_convert_optab (ZERO_EXTEND);
@@ -5135,6 +5137,8 @@ init_optabs (void)
   init_floating_libfuncs (le_optab, "le", '2');
   init_floating_libfuncs (unord_optab, "unord", '2');
 
+  init_floating_libfuncs (powi_optab, "powi", '2');
+
   /* Conversions.  */
   init_interclass_conv_libfuncs (sfloat_optab, "float",
                                 MODE_INT, MODE_FLOAT);
index 613831a82496f48ee49a756856026bcf47b2d409..621136be635cfc6a3903d646c18462c0b41886db 100644 (file)
@@ -235,6 +235,9 @@ enum optab_index
   /* Extract specified elements from vectors, for vector load.  */
   OTI_vec_realign_load,
 
+  /* Perform a raise to the power of integer.  */
+  OTI_powi,
+
   OTI_MAX
 };
 
@@ -340,6 +343,8 @@ extern GTY(()) optab optab_table[OTI_MAX];
 #define vec_init_optab (optab_table[OTI_vec_init])
 #define vec_realign_load_optab (optab_table[OTI_vec_realign_load])
 
+#define powi_optab (optab_table[OTI_powi])
+
 /* Conversion optabs have their own table and indexes.  */
 enum convert_optab_index
 {
index 135e31dabd65cdf98e801d50a849b054800549a8..2cfb809faf3cc1cb2e8b58b767c2a00fa76373ea 100644 (file)
@@ -1,3 +1,9 @@
+2005-02-09  Richard Guenther  <rguenth@gcc.gnu.org>
+
+       PR middle-end/19402
+       * gcc.dg/pr19402-1.c: New testcase.
+       * gcc.dg/pr19402-2.c: likewise.
+
 2005-02-09  Richard Guenther  <rguenth@gcc.gnu.org>
 
        PR middle-end/19854
diff --git a/gcc/testsuite/gcc.dg/pr19402-1.c b/gcc/testsuite/gcc.dg/pr19402-1.c
new file mode 100644 (file)
index 0000000..866ac63
--- /dev/null
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+float test_powif(float x)
+{
+  return __builtin_powif(x, -1)
+        + __builtin_powif(x, 0)
+        + __builtin_powif(x, 1)
+        + __builtin_powif(x, 2);
+}
+
+double test_powi(double x)
+{
+  return __builtin_powi(x, -1)
+        + __builtin_powi(x, 0)
+        + __builtin_powi(x, 1)
+        + __builtin_powi(x, 2);
+}
+
+long double test_powil(long double x)
+{
+  return __builtin_powil(x, -1)
+        + __builtin_powil(x, 0)
+        + __builtin_powil(x, 1)
+        + __builtin_powil(x, 2);
+}
+
+/* { dg-final { scan-assembler-not "__builtin_" } } */
+
diff --git a/gcc/testsuite/gcc.dg/pr19402-2.c b/gcc/testsuite/gcc.dg/pr19402-2.c
new file mode 100644 (file)
index 0000000..1902227
--- /dev/null
@@ -0,0 +1,82 @@
+/* { dg-do run } */
+/* { dg-options "-fno-inline -Os" } */
+
+void abort(void);
+
+
+float powif(float x, int n)
+{
+  return __builtin_powif(x, n);
+}
+
+double powi(double x, int n)
+{
+  return __builtin_powi(x, n);
+}
+
+long double powil(long double x, int n)
+{
+  return __builtin_powil(x, n);
+}
+
+
+float powcif(float x)
+{
+  return __builtin_powif(x, 5);
+}
+
+double powci(double x)
+{
+  return __builtin_powi(x, 5);
+}
+
+long double powcil(long double x)
+{
+  return __builtin_powil(x, 5);
+}
+
+
+float powicf(int n)
+{
+  return __builtin_powif(2.0, n);
+}
+
+double powic(int n)
+{
+  return __builtin_powi(2.0, n);
+}
+
+long double powicl(int n)
+{
+  return __builtin_powil(2.0, n);
+}
+
+
+int main()
+{
+  if (__builtin_powi(1.0, 5) != 1.0)
+    abort();
+  if (__builtin_powif(1.0, 5) != 1.0)
+    abort();
+  if (__builtin_powil(1.0, 5) != 1.0)
+    abort();
+  if (powci(1.0) != 1.0)
+    abort();
+  if (powcif(1.0) != 1.0)
+    abort();
+  if (powcil(1.0) != 1.0)
+    abort();
+  if (powi(1.0, -5) != 1.0)
+    abort();
+  if (powif(1.0, -5) != 1.0)
+    abort();
+  if (powil(1.0, -5) != 1.0)
+    abort();
+  if (powic(1) != 2.0)
+    abort();
+  if (powicf(1) != 2.0)
+    abort();
+  if (powicl(1) != 2.0)
+    abort();
+  return 0;
+}