aboutsummaryrefslogtreecommitdiff
path: root/gcc/optabs-tree.c
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2015-09-17 14:28:59 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2015-09-17 14:28:59 +0000
commit385399a8759c233f487ddd7e158802a1ee4f960d (patch)
treeb4c04d6027cb1108af25cc0d42827303e661abb5 /gcc/optabs-tree.c
parenta78eb72ac066743c8c11dbc1032a1909963719a3 (diff)
downloadgcc-385399a8759c233f487ddd7e158802a1ee4f960d.zip
gcc-385399a8759c233f487ddd7e158802a1ee4f960d.tar.gz
gcc-385399a8759c233f487ddd7e158802a1ee4f960d.tar.bz2
Split up optabs.[hc]
optabs.[hc] is a bit of a behemoth. It includes basic functions for querying what a target can do, related tree- and gimple-level query functions, related rtl-level query functions, and the functions that actually generate code. Some gimple optimisations therefore need: #include "insn-config.h" #include "expmed.h" #include "dojump.h" #include "explow.h" #include "emit-rtl.h" #include "varasm.h" #include "stmt.h" #include "expr.h" purely to query whether the target has support for a particular operation. This patch splits optabs up as follows: - optabs-query.[hc]: IL-independent functions for querying what a target can do natively. - optabs-tree.[hc]: tree and gimple query functions (an extension of optabs-query.[hc]). - optabs-libfuncs.[hc]: optabs-specific libfuncs (an extension of libfuncs.h) - optabs.h: For now includes optabs-query.h and optabs-libfuncs.h. Only two files outside optabs need to include both optabs.h and optabs-tree.h: expr.c and function.c. I think that's expected given that both are related to expand. It might be good to split optabs.h further, but this is already quite a big patch. I changed can_conditionally_move_p from returning an int to returning a bool and fixed a few formatting glitches. There should be no other changes to the functions themselves. gcc/ * Makefile.in (OBJS): Add optabs-libfuncs.o, optabs-query.o and optabs-tree.o. (GTFILES): Replace optabs.c with optabs-libfunc.c. * genopinit.c (main): Add an include guard to insn-opinit.h. Protect the rtx_code parts with NUM_RTX_CODE. * optabs.h: Split parts out to... * optabs-libfuncs.h, optabs-query.h, optabs-tree.h: ...these new files. * optabs.c: Split parts out to... * optabs-libfuncs.c, optabs-query.c, optabs-tree.c: ...these new files. * cilk-common.c: Include optabs-query.h rather than optabs.h. * fold-const.c: Likewise. * target-globals.c: Likewise. * tree-if-conv.c: Likewise. * tree-ssa-forwprop.c: Likewise. * tree-ssa-loop-prefetch.c: Likewise. * tree-ssa-math-opts.c: Include optabs-tree.h rather than optabs.h. Remove unncessary include files. * tree-ssa-phiopt.c: Likewise. * tree-ssa-reassoc.c: Likewise. * tree-switch-conversion.c: Likewise. * tree-vect-data-refs.c: Likewise. * tree-vect-generic.c: Likewise. * tree-vect-loop.c: Likewise. * tree-vect-patterns.c: Likewise. * tree-vect-slp.c: Likewise. * tree-vect-stmts.c: Likewise. * tree-vrp.c: Likewise. * toplev.c: Include optabs-query.h and optabs-libfuncs.h rather than optabs.h. * expr.c: Include optabs-tree.h. * function.c: Likewise. From-SVN: r227865
Diffstat (limited to 'gcc/optabs-tree.c')
-rw-r--r--gcc/optabs-tree.c370
1 files changed, 370 insertions, 0 deletions
diff --git a/gcc/optabs-tree.c b/gcc/optabs-tree.c
new file mode 100644
index 0000000..3b03338
--- /dev/null
+++ b/gcc/optabs-tree.c
@@ -0,0 +1,370 @@
+/* Tree-based target query functions relating to optabs
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "insn-codes.h"
+#include "tree.h"
+#include "optabs-tree.h"
+#include "stor-layout.h"
+
+/* Return the optab used for computing the operation given by the tree code,
+ CODE and the tree EXP. This function is not always usable (for example, it
+ cannot give complete results for multiplication or division) but probably
+ ought to be relied on more widely throughout the expander. */
+optab
+optab_for_tree_code (enum tree_code code, const_tree type,
+ enum optab_subtype subtype)
+{
+ bool trapv;
+ switch (code)
+ {
+ case BIT_AND_EXPR:
+ return and_optab;
+
+ case BIT_IOR_EXPR:
+ return ior_optab;
+
+ case BIT_NOT_EXPR:
+ return one_cmpl_optab;
+
+ case BIT_XOR_EXPR:
+ return xor_optab;
+
+ case MULT_HIGHPART_EXPR:
+ return TYPE_UNSIGNED (type) ? umul_highpart_optab : smul_highpart_optab;
+
+ case TRUNC_MOD_EXPR:
+ case CEIL_MOD_EXPR:
+ case FLOOR_MOD_EXPR:
+ case ROUND_MOD_EXPR:
+ return TYPE_UNSIGNED (type) ? umod_optab : smod_optab;
+
+ case RDIV_EXPR:
+ case TRUNC_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case ROUND_DIV_EXPR:
+ case EXACT_DIV_EXPR:
+ if (TYPE_SATURATING (type))
+ return TYPE_UNSIGNED (type) ? usdiv_optab : ssdiv_optab;
+ return TYPE_UNSIGNED (type) ? udiv_optab : sdiv_optab;
+
+ case LSHIFT_EXPR:
+ if (TREE_CODE (type) == VECTOR_TYPE)
+ {
+ if (subtype == optab_vector)
+ return TYPE_SATURATING (type) ? unknown_optab : vashl_optab;
+
+ gcc_assert (subtype == optab_scalar);
+ }
+ if (TYPE_SATURATING (type))
+ return TYPE_UNSIGNED (type) ? usashl_optab : ssashl_optab;
+ return ashl_optab;
+
+ case RSHIFT_EXPR:
+ if (TREE_CODE (type) == VECTOR_TYPE)
+ {
+ if (subtype == optab_vector)
+ return TYPE_UNSIGNED (type) ? vlshr_optab : vashr_optab;
+
+ gcc_assert (subtype == optab_scalar);
+ }
+ return TYPE_UNSIGNED (type) ? lshr_optab : ashr_optab;
+
+ case LROTATE_EXPR:
+ if (TREE_CODE (type) == VECTOR_TYPE)
+ {
+ if (subtype == optab_vector)
+ return vrotl_optab;
+
+ gcc_assert (subtype == optab_scalar);
+ }
+ return rotl_optab;
+
+ case RROTATE_EXPR:
+ if (TREE_CODE (type) == VECTOR_TYPE)
+ {
+ if (subtype == optab_vector)
+ return vrotr_optab;
+
+ gcc_assert (subtype == optab_scalar);
+ }
+ return rotr_optab;
+
+ case MAX_EXPR:
+ return TYPE_UNSIGNED (type) ? umax_optab : smax_optab;
+
+ case MIN_EXPR:
+ return TYPE_UNSIGNED (type) ? umin_optab : smin_optab;
+
+ case REALIGN_LOAD_EXPR:
+ return vec_realign_load_optab;
+
+ case WIDEN_SUM_EXPR:
+ return TYPE_UNSIGNED (type) ? usum_widen_optab : ssum_widen_optab;
+
+ case DOT_PROD_EXPR:
+ return TYPE_UNSIGNED (type) ? udot_prod_optab : sdot_prod_optab;
+
+ case SAD_EXPR:
+ return TYPE_UNSIGNED (type) ? usad_optab : ssad_optab;
+
+ case WIDEN_MULT_PLUS_EXPR:
+ return (TYPE_UNSIGNED (type)
+ ? (TYPE_SATURATING (type)
+ ? usmadd_widen_optab : umadd_widen_optab)
+ : (TYPE_SATURATING (type)
+ ? ssmadd_widen_optab : smadd_widen_optab));
+
+ case WIDEN_MULT_MINUS_EXPR:
+ return (TYPE_UNSIGNED (type)
+ ? (TYPE_SATURATING (type)
+ ? usmsub_widen_optab : umsub_widen_optab)
+ : (TYPE_SATURATING (type)
+ ? ssmsub_widen_optab : smsub_widen_optab));
+
+ case FMA_EXPR:
+ return fma_optab;
+
+ case REDUC_MAX_EXPR:
+ return TYPE_UNSIGNED (type)
+ ? reduc_umax_scal_optab : reduc_smax_scal_optab;
+
+ case REDUC_MIN_EXPR:
+ return TYPE_UNSIGNED (type)
+ ? reduc_umin_scal_optab : reduc_smin_scal_optab;
+
+ case REDUC_PLUS_EXPR:
+ return reduc_plus_scal_optab;
+
+ case VEC_WIDEN_MULT_HI_EXPR:
+ return TYPE_UNSIGNED (type) ?
+ vec_widen_umult_hi_optab : vec_widen_smult_hi_optab;
+
+ case VEC_WIDEN_MULT_LO_EXPR:
+ return TYPE_UNSIGNED (type) ?
+ vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;
+
+ case VEC_WIDEN_MULT_EVEN_EXPR:
+ return TYPE_UNSIGNED (type) ?
+ vec_widen_umult_even_optab : vec_widen_smult_even_optab;
+
+ case VEC_WIDEN_MULT_ODD_EXPR:
+ return TYPE_UNSIGNED (type) ?
+ vec_widen_umult_odd_optab : vec_widen_smult_odd_optab;
+
+ case VEC_WIDEN_LSHIFT_HI_EXPR:
+ return TYPE_UNSIGNED (type) ?
+ vec_widen_ushiftl_hi_optab : vec_widen_sshiftl_hi_optab;
+
+ case VEC_WIDEN_LSHIFT_LO_EXPR:
+ return TYPE_UNSIGNED (type) ?
+ vec_widen_ushiftl_lo_optab : vec_widen_sshiftl_lo_optab;
+
+ case VEC_UNPACK_HI_EXPR:
+ return TYPE_UNSIGNED (type) ?
+ vec_unpacku_hi_optab : vec_unpacks_hi_optab;
+
+ case VEC_UNPACK_LO_EXPR:
+ return TYPE_UNSIGNED (type) ?
+ vec_unpacku_lo_optab : vec_unpacks_lo_optab;
+
+ case VEC_UNPACK_FLOAT_HI_EXPR:
+ /* The signedness is determined from input operand. */
+ return TYPE_UNSIGNED (type) ?
+ vec_unpacku_float_hi_optab : vec_unpacks_float_hi_optab;
+
+ case VEC_UNPACK_FLOAT_LO_EXPR:
+ /* The signedness is determined from input operand. */
+ return TYPE_UNSIGNED (type) ?
+ vec_unpacku_float_lo_optab : vec_unpacks_float_lo_optab;
+
+ case VEC_PACK_TRUNC_EXPR:
+ return vec_pack_trunc_optab;
+
+ case VEC_PACK_SAT_EXPR:
+ return TYPE_UNSIGNED (type) ? vec_pack_usat_optab : vec_pack_ssat_optab;
+
+ case VEC_PACK_FIX_TRUNC_EXPR:
+ /* The signedness is determined from output operand. */
+ return TYPE_UNSIGNED (type) ?
+ vec_pack_ufix_trunc_optab : vec_pack_sfix_trunc_optab;
+
+ default:
+ break;
+ }
+
+ trapv = INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type);
+ switch (code)
+ {
+ case POINTER_PLUS_EXPR:
+ case PLUS_EXPR:
+ if (TYPE_SATURATING (type))
+ return TYPE_UNSIGNED (type) ? usadd_optab : ssadd_optab;
+ return trapv ? addv_optab : add_optab;
+
+ case MINUS_EXPR:
+ if (TYPE_SATURATING (type))
+ return TYPE_UNSIGNED (type) ? ussub_optab : sssub_optab;
+ return trapv ? subv_optab : sub_optab;
+
+ case MULT_EXPR:
+ if (TYPE_SATURATING (type))
+ return TYPE_UNSIGNED (type) ? usmul_optab : ssmul_optab;
+ return trapv ? smulv_optab : smul_optab;
+
+ case NEGATE_EXPR:
+ if (TYPE_SATURATING (type))
+ return TYPE_UNSIGNED (type) ? usneg_optab : ssneg_optab;
+ return trapv ? negv_optab : neg_optab;
+
+ case ABS_EXPR:
+ return trapv ? absv_optab : abs_optab;
+
+ default:
+ return unknown_optab;
+ }
+}
+
+/* Given optab UNOPTAB that reduces a vector to a scalar, find instead the old
+ optab that produces a vector with the reduction result in one element,
+ for a tree with type TYPE. */
+
+optab
+scalar_reduc_to_vector (optab unoptab, const_tree type)
+{
+ switch (unoptab)
+ {
+ case reduc_plus_scal_optab:
+ return TYPE_UNSIGNED (type) ? reduc_uplus_optab : reduc_splus_optab;
+
+ case reduc_smin_scal_optab: return reduc_smin_optab;
+ case reduc_umin_scal_optab: return reduc_umin_optab;
+ case reduc_smax_scal_optab: return reduc_smax_optab;
+ case reduc_umax_scal_optab: return reduc_umax_optab;
+ default: return unknown_optab;
+ }
+}
+
+/* Function supportable_convert_operation
+
+ Check whether an operation represented by the code CODE is a
+ convert operation that is supported by the target platform in
+ vector form (i.e., when operating on arguments of type VECTYPE_IN
+ producing a result of type VECTYPE_OUT).
+
+ Convert operations we currently support directly are FIX_TRUNC and FLOAT.
+ This function checks if these operations are supported
+ by the target platform either directly (via vector tree-codes), or via
+ target builtins.
+
+ Output:
+ - CODE1 is code of vector operation to be used when
+ vectorizing the operation, if available.
+ - DECL is decl of target builtin functions to be used
+ when vectorizing the operation, if available. In this case,
+ CODE1 is CALL_EXPR. */
+
+bool
+supportable_convert_operation (enum tree_code code,
+ tree vectype_out, tree vectype_in,
+ tree *decl, enum tree_code *code1)
+{
+ machine_mode m1,m2;
+ bool truncp;
+
+ m1 = TYPE_MODE (vectype_out);
+ m2 = TYPE_MODE (vectype_in);
+
+ /* First check if we can done conversion directly. */
+ if ((code == FIX_TRUNC_EXPR
+ && can_fix_p (m1,m2,TYPE_UNSIGNED (vectype_out), &truncp)
+ != CODE_FOR_nothing)
+ || (code == FLOAT_EXPR
+ && can_float_p (m1,m2,TYPE_UNSIGNED (vectype_in))
+ != CODE_FOR_nothing))
+ {
+ *code1 = code;
+ return true;
+ }
+
+ /* Now check for builtin. */
+ if (targetm.vectorize.builtin_conversion
+ && targetm.vectorize.builtin_conversion (code, vectype_out, vectype_in))
+ {
+ *code1 = CALL_EXPR;
+ *decl = targetm.vectorize.builtin_conversion (code, vectype_out,
+ vectype_in);
+ return true;
+ }
+ return false;
+}
+
+/* Return TRUE iff, appropriate vector insns are available
+ for vector cond expr with vector type VALUE_TYPE and a comparison
+ with operand vector types in CMP_OP_TYPE. */
+
+bool
+expand_vec_cond_expr_p (tree value_type, tree cmp_op_type)
+{
+ machine_mode value_mode = TYPE_MODE (value_type);
+ machine_mode cmp_op_mode = TYPE_MODE (cmp_op_type);
+ if (GET_MODE_SIZE (value_mode) != GET_MODE_SIZE (cmp_op_mode)
+ || GET_MODE_NUNITS (value_mode) != GET_MODE_NUNITS (cmp_op_mode)
+ || get_vcond_icode (TYPE_MODE (value_type), TYPE_MODE (cmp_op_type),
+ TYPE_UNSIGNED (cmp_op_type)) == CODE_FOR_nothing)
+ return false;
+ return true;
+}
+
+/* Use the current target and options to initialize
+ TREE_OPTIMIZATION_OPTABS (OPTNODE). */
+
+void
+init_tree_optimization_optabs (tree optnode)
+{
+ /* Quick exit if we have already computed optabs for this target. */
+ if (TREE_OPTIMIZATION_BASE_OPTABS (optnode) == this_target_optabs)
+ return;
+
+ /* Forget any previous information and set up for the current target. */
+ TREE_OPTIMIZATION_BASE_OPTABS (optnode) = this_target_optabs;
+ struct target_optabs *tmp_optabs = (struct target_optabs *)
+ TREE_OPTIMIZATION_OPTABS (optnode);
+ if (tmp_optabs)
+ memset (tmp_optabs, 0, sizeof (struct target_optabs));
+ else
+ tmp_optabs = ggc_alloc<target_optabs> ();
+
+ /* Generate a new set of optabs into tmp_optabs. */
+ init_all_optabs (tmp_optabs);
+
+ /* If the optabs changed, record it. */
+ if (memcmp (tmp_optabs, this_target_optabs, sizeof (struct target_optabs)))
+ TREE_OPTIMIZATION_OPTABS (optnode) = tmp_optabs;
+ else
+ {
+ TREE_OPTIMIZATION_OPTABS (optnode) = NULL;
+ ggc_free (tmp_optabs);
+ }
+}