diff options
author | Richard Sandiford <richard.sandiford@arm.com> | 2015-11-17 18:39:02 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2015-11-17 18:39:02 +0000 |
commit | 686ee9719a4dc70619da0a69a4357007406c9fbd (patch) | |
tree | a3ec02e033084a3f11a50a026441973f162ceda0 /gcc/internal-fn.c | |
parent | ab23f5d9742b8b1c7a80d8383a141f243f4198e6 (diff) | |
download | gcc-686ee9719a4dc70619da0a69a4357007406c9fbd.zip gcc-686ee9719a4dc70619da0a69a4357007406c9fbd.tar.gz gcc-686ee9719a4dc70619da0a69a4357007406c9fbd.tar.bz2 |
Add internal math functions
This patch adds internal functions for simple FLT_FN built-in functions,
in cases where an associated optab already exists. Unlike some of the
built-in functions, these internal functions never set errno.
LDEXP is an odd-one out in that its second operand is an integer.
All the others operate on uniform types.
The patch also adds a function to query the internal function associated
with a built-in function (if any), and another to test whether a given
gcall could be replaced by a call to an internal function on the current
target (as long as the caller deals with errno appropriately).
Tested on x86_64-linux-gnu, aarch64-linux-gnu and arm-linux-gnueabi.
gcc/
* builtins.h (associated_internal_fn): Declare.
(replacement_internal_fn): Likewise.
* builtins.c: Include internal-fn.h
(associated_internal_fn, replacement_internal_fn): New functions.
* internal-fn.def (DEF_INTERNAL_FLT_FN): New macro.
(ACOS, ASIN, ATAN, COS, EXP, EXP10, EXP2, EXPM1, LOG, LOG10, LOG1P)
(LOG2, LOGB, SIGNIFICAND, SIN, SQRT, TAN, CEIL, FLOOR, NEARBYINT)
(RINT, ROUND, TRUNC, ATAN2, COPYSIGN, FMOD, POW, REMAINDER, SCALB)
(LDEXP): New functions.
* internal-fn.c: Include recog.h.
(unary_direct, binary_direct): New macros.
(expand_direct_optab_fn): New function.
(expand_unary_optab_fn): New macro.
(expand_binary_optab_fn): Likewise.
(direct_unary_optab_supported_p): Likewise.
(direct_binary_optab_supported_p): Likewise.
From-SVN: r230474
Diffstat (limited to 'gcc/internal-fn.c')
-rw-r--r-- | gcc/internal-fn.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index e77006d..b853162 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "dojump.h" #include "expr.h" #include "ubsan.h" +#include "recog.h" /* The names of each internal function, indexed by function number. */ const char *const internal_fn_name_array[] = { @@ -73,6 +74,8 @@ init_internal_fns () #define load_lanes_direct { -1, -1 } #define mask_store_direct { 3, 2 } #define store_lanes_direct { 0, 0 } +#define unary_direct { 0, 0 } +#define binary_direct { 0, 0 } const direct_internal_fn_info direct_internal_fn_array[IFN_LAST + 1] = { #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) not_direct, @@ -2070,6 +2073,58 @@ expand_GOACC_REDUCTION (gcall *stmt ATTRIBUTE_UNUSED) gcc_unreachable (); } +/* Expand call STMT using OPTAB, which has a single output operand and + NARGS input operands. */ + +static void +expand_direct_optab_fn (gcall *stmt, direct_optab optab, unsigned int nargs) +{ + expand_operand *ops = XALLOCAVEC (expand_operand, nargs + 1); + + internal_fn fn = gimple_call_internal_fn (stmt); + tree_pair types = direct_internal_fn_types (fn, stmt); + insn_code icode = direct_optab_handler (optab, TYPE_MODE (types.first)); + + tree lhs = gimple_call_lhs (stmt); + tree lhs_type = TREE_TYPE (lhs); + rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE); + create_output_operand (&ops[0], lhs_rtx, insn_data[icode].operand[0].mode); + + for (unsigned int i = 0; i < nargs; ++i) + { + tree rhs = gimple_call_arg (stmt, i); + tree rhs_type = TREE_TYPE (rhs); + rtx rhs_rtx = expand_normal (rhs); + if (INTEGRAL_TYPE_P (rhs_type)) + create_convert_operand_from (&ops[i + 1], rhs_rtx, + TYPE_MODE (rhs_type), + TYPE_UNSIGNED (rhs_type)); + else + create_input_operand (&ops[i + 1], rhs_rtx, TYPE_MODE (rhs_type)); + } + + expand_insn (icode, nargs + 1, ops); + if (!rtx_equal_p (lhs_rtx, ops[0].value)) + { + if (INTEGRAL_TYPE_P (lhs_type)) + /* Convert the operand to the required type, which is useful + for things that return an int regardless of the size of + the input. If the value produced by the instruction is + smaller than required, assume that it is signed. */ + convert_move (lhs_rtx, ops[0].value, 0); + else + emit_move_insn (lhs_rtx, ops[0].value); + } +} + +/* Expanders for optabs that can use expand_direct_optab_fn. */ + +#define expand_unary_optab_fn(STMT, OPTAB) \ + expand_direct_optab_fn (STMT, OPTAB, 1) + +#define expand_binary_optab_fn(STMT, OPTAB) \ + expand_direct_optab_fn (STMT, OPTAB, 2) + /* RETURN_TYPE and ARGS are a return type and argument list that are in principle compatible with FN (which satisfies direct_internal_fn_p). Return the types that should be used to determine whether the @@ -2121,6 +2176,8 @@ multi_vector_optab_supported_p (convert_optab optab, tree_pair types) return get_multi_vector_move (types.first, optab) != CODE_FOR_nothing; } +#define direct_unary_optab_supported_p direct_optab_supported_p +#define direct_binary_optab_supported_p direct_optab_supported_p #define direct_mask_load_optab_supported_p direct_optab_supported_p #define direct_load_lanes_optab_supported_p multi_vector_optab_supported_p #define direct_mask_store_optab_supported_p direct_optab_supported_p |