diff options
-rw-r--r-- | gcc/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/builtins.c | 69 | ||||
-rw-r--r-- | gcc/builtins.def | 3 | ||||
-rw-r--r-- | gcc/doc/extend.texi | 18 | ||||
-rw-r--r-- | gcc/libgcc-std.ver | 9 | ||||
-rw-r--r-- | gcc/libgcc2.c | 36 | ||||
-rw-r--r-- | gcc/libgcc2.h | 4 | ||||
-rw-r--r-- | gcc/mklibgcc.in | 3 | ||||
-rw-r--r-- | gcc/optabs.c | 4 | ||||
-rw-r--r-- | gcc/optabs.h | 5 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr19402-1.c | 29 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr19402-2.c | 82 |
13 files changed, 281 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 20bc95669ff..60107b013c3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/builtins.c b/gcc/builtins.c index 09c5b6b795e..36316156c5f 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -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: diff --git a/gcc/builtins.def b/gcc/builtins.def index 9fc347f7369..972b6a2ee83 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -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) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index e730511c212..7e4d66aaa87 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -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 diff --git a/gcc/libgcc-std.ver b/gcc/libgcc-std.ver index db68ea6ef94..b701fcf9533 100644 --- a/gcc/libgcc-std.ver +++ b/gcc/libgcc-std.ver @@ -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 diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c index 1b1455d5d8d..2d47c0d7f64 100644 --- a/gcc/libgcc2.c +++ b/gcc/libgcc2.c @@ -1465,6 +1465,42 @@ __fixunssfSI (SFtype a) } #endif +/* 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 + /* From here on down, the routines use normal data types. */ #define SItype bogus_type diff --git a/gcc/libgcc2.h b/gcc/libgcc2.h index f6b8fa43aef..025dd6f5aef 100644 --- a/gcc/libgcc2.h +++ b/gcc/libgcc2.h @@ -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 */ diff --git a/gcc/mklibgcc.in b/gcc/mklibgcc.in index 3cdd4bb96e7..7ac1dbf24de 100644 --- a/gcc/mklibgcc.in +++ b/gcc/mklibgcc.in @@ -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 diff --git a/gcc/optabs.c b/gcc/optabs.c index 889f9156dd1..75c78cd9b2d 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -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); diff --git a/gcc/optabs.h b/gcc/optabs.h index 613831a8249..621136be635 100644 --- a/gcc/optabs.h +++ b/gcc/optabs.h @@ -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 { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 135e31dabd6..2cfb809faf3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,11 @@ 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 * g++.dg/tree-ssa/tmmti.C: New testcase. diff --git a/gcc/testsuite/gcc.dg/pr19402-1.c b/gcc/testsuite/gcc.dg/pr19402-1.c new file mode 100644 index 00000000000..866ac63cb7e --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr19402-1.c @@ -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 index 00000000000..1902227a6e0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr19402-2.c @@ -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; +} |