diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 19 | ||||
-rw-r--r-- | gcc/builtins.c | 58 | ||||
-rw-r--r-- | gcc/builtins.h | 3 | ||||
-rw-r--r-- | gcc/internal-fn.c | 57 | ||||
-rw-r--r-- | gcc/internal-fn.def | 50 |
5 files changed, 187 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bdb295c..504138e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,24 @@ 2015-11-17 Richard Sandiford <richard.sandiford@arm.com> + * 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. + +2015-11-17 Richard Sandiford <richard.sandiford@arm.com> + * coretypes.h (tree_pair): New type. * internal-fn.def (DEF_INTERNAL_OPTAB_FN): New macro. Use it for MASK_LOAD, LOAD_LANES, MASK_STORE and STORE_LANES. diff --git a/gcc/builtins.c b/gcc/builtins.c index 85b251a..0eef112 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -62,6 +62,7 @@ along with GCC; see the file COPYING3. If not see #include "cilk.h" #include "tree-chkp.h" #include "rtl-chkp.h" +#include "internal-fn.h" struct target_builtins default_target_builtins; @@ -1901,6 +1902,63 @@ mathfn_built_in (tree type, enum built_in_function fn) return mathfn_built_in_1 (type, fn, /*implicit=*/ 1); } +/* If BUILT_IN_NORMAL function FNDECL has an associated internal function, + return its code, otherwise return IFN_LAST. Note that this function + only tests whether the function is defined in internals.def, not whether + it is actually available on the target. */ + +internal_fn +associated_internal_fn (tree fndecl) +{ + gcc_checking_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL); + tree return_type = TREE_TYPE (TREE_TYPE (fndecl)); + switch (DECL_FUNCTION_CODE (fndecl)) + { +#define DEF_INTERNAL_FLT_FN(NAME, FLAGS, OPTAB, TYPE) \ + CASE_FLT_FN (BUILT_IN_##NAME): return IFN_##NAME; +#include "internal-fn.def" + + CASE_FLT_FN (BUILT_IN_POW10): + return IFN_EXP10; + + CASE_FLT_FN (BUILT_IN_DREM): + return IFN_REMAINDER; + + CASE_FLT_FN (BUILT_IN_SCALBN): + CASE_FLT_FN (BUILT_IN_SCALBLN): + if (REAL_MODE_FORMAT (TYPE_MODE (return_type))->b == 2) + return IFN_LDEXP; + return IFN_LAST; + + default: + return IFN_LAST; + } +} + +/* If CALL is a call to a BUILT_IN_NORMAL function that could be replaced + on the current target by a call to an internal function, return the + code of that internal function, otherwise return IFN_LAST. The caller + is responsible for ensuring that any side-effects of the built-in + call are dealt with correctly. E.g. if CALL sets errno, the caller + must decide that the errno result isn't needed or make it available + in some other way. */ + +internal_fn +replacement_internal_fn (gcall *call) +{ + if (gimple_call_builtin_p (call, BUILT_IN_NORMAL)) + { + internal_fn ifn = associated_internal_fn (gimple_call_fndecl (call)); + if (ifn != IFN_LAST) + { + tree_pair types = direct_internal_fn_types (ifn, call); + if (direct_internal_fn_supported_p (ifn, types)) + return ifn; + } + } + return IFN_LAST; +} + /* 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. */ diff --git a/gcc/builtins.h b/gcc/builtins.h index b039632..7f92d07 100644 --- a/gcc/builtins.h +++ b/gcc/builtins.h @@ -94,4 +94,7 @@ extern char target_percent_s[3]; extern char target_percent_c[3]; extern char target_percent_s_newline[4]; +extern internal_fn associated_internal_fn (tree); +extern internal_fn replacement_internal_fn (gcall *); + #endif 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 diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index a5f6df2..65e158e 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see DEF_INTERNAL_FN (NAME, FLAGS, FNSPEC) DEF_INTERNAL_OPTAB_FN (NAME, FLAGS, OPTAB, TYPE) + DEF_INTERNAL_FLT_FN (NAME, FLAGS, OPTAB, TYPE) where NAME is the name of the function, FLAGS is a set of ECF_* flags and FNSPEC is a string describing functions fnspec. @@ -47,6 +48,11 @@ along with GCC; see the file COPYING3. If not see - mask_store: currently just maskstore - store_lanes: currently just vec_store_lanes + DEF_INTERNAL_FLT_FN is like DEF_INTERNAL_OPTAB_FN, but in addition, + the function implements the computational part of a built-in math + function BUILT_IN_<NAME>{F,,L}. Unlike some built-in functions, + these internal functions never set errno. + Each entry must have a corresponding expander of the form: void expand_NAME (gimple_call stmt) @@ -64,12 +70,55 @@ along with GCC; see the file COPYING3. If not see DEF_INTERNAL_FN (NAME, FLAGS | ECF_LEAF, NULL) #endif +#ifndef DEF_INTERNAL_FLT_FN +#define DEF_INTERNAL_FLT_FN(NAME, FLAGS, OPTAB, TYPE) \ + DEF_INTERNAL_OPTAB_FN (NAME, FLAGS, OPTAB, TYPE) +#endif + DEF_INTERNAL_OPTAB_FN (MASK_LOAD, ECF_PURE, maskload, mask_load) DEF_INTERNAL_OPTAB_FN (LOAD_LANES, ECF_CONST, vec_load_lanes, load_lanes) DEF_INTERNAL_OPTAB_FN (MASK_STORE, 0, maskstore, mask_store) DEF_INTERNAL_OPTAB_FN (STORE_LANES, ECF_CONST, vec_store_lanes, store_lanes) +/* Unary math functions. */ +DEF_INTERNAL_FLT_FN (ACOS, ECF_CONST, acos, unary) +DEF_INTERNAL_FLT_FN (ASIN, ECF_CONST, asin, unary) +DEF_INTERNAL_FLT_FN (ATAN, ECF_CONST, atan, unary) +DEF_INTERNAL_FLT_FN (COS, ECF_CONST, cos, unary) +DEF_INTERNAL_FLT_FN (EXP, ECF_CONST, exp, unary) +DEF_INTERNAL_FLT_FN (EXP10, ECF_CONST, exp10, unary) +DEF_INTERNAL_FLT_FN (EXP2, ECF_CONST, exp2, unary) +DEF_INTERNAL_FLT_FN (EXPM1, ECF_CONST, expm1, unary) +DEF_INTERNAL_FLT_FN (LOG, ECF_CONST, log, unary) +DEF_INTERNAL_FLT_FN (LOG10, ECF_CONST, log10, unary) +DEF_INTERNAL_FLT_FN (LOG1P, ECF_CONST, log1p, unary) +DEF_INTERNAL_FLT_FN (LOG2, ECF_CONST, log2, unary) +DEF_INTERNAL_FLT_FN (LOGB, ECF_CONST, logb, unary) +DEF_INTERNAL_FLT_FN (SIGNIFICAND, ECF_CONST, significand, unary) +DEF_INTERNAL_FLT_FN (SIN, ECF_CONST, sin, unary) +DEF_INTERNAL_FLT_FN (SQRT, ECF_CONST, sqrt, unary) +DEF_INTERNAL_FLT_FN (TAN, ECF_CONST, tan, unary) + +/* FP rounding. */ +DEF_INTERNAL_FLT_FN (CEIL, ECF_CONST, ceil, unary) +DEF_INTERNAL_FLT_FN (FLOOR, ECF_CONST, floor, unary) +DEF_INTERNAL_FLT_FN (NEARBYINT, ECF_CONST, nearbyint, unary) +DEF_INTERNAL_FLT_FN (RINT, ECF_CONST, rint, unary) +DEF_INTERNAL_FLT_FN (ROUND, ECF_CONST, round, unary) +DEF_INTERNAL_FLT_FN (TRUNC, ECF_CONST, btrunc, unary) + +/* Binary math functions. */ +DEF_INTERNAL_FLT_FN (ATAN2, ECF_CONST, atan2, binary) +DEF_INTERNAL_FLT_FN (COPYSIGN, ECF_CONST, copysign, binary) +DEF_INTERNAL_FLT_FN (FMOD, ECF_CONST, fmod, binary) +DEF_INTERNAL_FLT_FN (POW, ECF_CONST, pow, binary) +DEF_INTERNAL_FLT_FN (REMAINDER, ECF_CONST, remainder, binary) +DEF_INTERNAL_FLT_FN (SCALB, ECF_CONST, scalb, binary) + +/* FP scales. */ +DEF_INTERNAL_FLT_FN (LDEXP, ECF_CONST, ldexp, binary) + DEF_INTERNAL_FN (GOMP_SIMD_LANE, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (GOMP_SIMD_VF, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (GOMP_SIMD_LAST_LANE, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) @@ -114,5 +163,6 @@ DEF_INTERNAL_FN (GOACC_LOOP, ECF_PURE | ECF_NOTHROW, NULL) /* OpenACC reduction abstraction. See internal-fn.h for usage. */ DEF_INTERNAL_FN (GOACC_REDUCTION, ECF_NOTHROW | ECF_LEAF, NULL) +#undef DEF_INTERNAL_FLT_FN #undef DEF_INTERNAL_OPTAB_FN #undef DEF_INTERNAL_FN |