aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog30
-rw-r--r--gcc/coretypes.h2
-rw-r--r--gcc/internal-fn.c144
-rw-r--r--gcc/internal-fn.def40
-rw-r--r--gcc/internal-fn.h38
5 files changed, 233 insertions, 21 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 74c7cf9..bdb295c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,35 @@
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.
+ * internal-fn.h (direct_internal_fn_info): New structure.
+ (direct_internal_fn_array): Declare.
+ (direct_internal_fn_p, direct_internal_fn): New functions.
+ (direct_internal_fn_types, direct_internal_fn_supported_p): Declare.
+ * internal-fn.c (not_direct, mask_load_direct, load_lanes_direct)
+ (mask_store_direct, store_lanes_direct): New macros.
+ (direct_internal_fn_array) New array.
+ (get_multi_vector_move): Return the optab handler without asserting
+ that it is available.
+ (expand_LOAD_LANES): Rename to...
+ (expand_load_lanes_optab_fn): ...this and add an optab argument.
+ (expand_STORE_LANES): Rename to...
+ (expand_store_lanes_optab_fn): ...this and add an optab argument.
+ (expand_MASK_LOAD): Rename to...
+ (expand_mask_load_optab_fn): ...this and add an optab argument.
+ (expand_MASK_STORE): Rename to...
+ (expand_mask_store_optab_fn): ...this and add an optab argument.
+ (direct_internal_fn_types, direct_optab_supported_p)
+ (multi_vector_optab_supported_p, direct_internal_fn_supported_p)
+ (direct_internal_fn_supported_p): New functions.
+ (direct_mask_load_optab_supported_p): New macro.
+ (direct_load_lanes_optab_supported_p): Likewise.
+ (direct_mask_store_optab_supported_p): Likewise.
+ (direct_store_lanes_optab_supported_p): Likewise.
+
+2015-11-17 Richard Sandiford <richard.sandiford@arm.com>
+
* tree-core.h (internal_fn): Move immediately after the definition
of built_in_function.
(combined_fn): New enum.
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 3439c38..d4a75db 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -251,6 +251,8 @@ namespace gcc {
class context;
}
+typedef std::pair <tree, tree> tree_pair;
+
#else
struct _dont_use_rtx_here_;
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 79425ea..e77006d 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -66,13 +66,27 @@ init_internal_fns ()
internal_fn_fnspec_array[IFN_LAST] = 0;
}
+/* Create static initializers for the information returned by
+ direct_internal_fn. */
+#define not_direct { -2, -2 }
+#define mask_load_direct { -1, 2 }
+#define load_lanes_direct { -1, -1 }
+#define mask_store_direct { 3, 2 }
+#define store_lanes_direct { 0, 0 }
+
+const direct_internal_fn_info direct_internal_fn_array[IFN_LAST + 1] = {
+#define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) not_direct,
+#define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) TYPE##_direct,
+#include "internal-fn.def"
+ not_direct
+};
+
/* ARRAY_TYPE is an array of vector modes. Return the associated insn
- for load-lanes-style optab OPTAB. The insn must exist. */
+ for load-lanes-style optab OPTAB, or CODE_FOR_nothing if none. */
static enum insn_code
get_multi_vector_move (tree array_type, convert_optab optab)
{
- enum insn_code icode;
machine_mode imode;
machine_mode vmode;
@@ -80,15 +94,13 @@ get_multi_vector_move (tree array_type, convert_optab optab)
imode = TYPE_MODE (array_type);
vmode = TYPE_MODE (TREE_TYPE (array_type));
- icode = convert_optab_handler (optab, imode, vmode);
- gcc_assert (icode != CODE_FOR_nothing);
- return icode;
+ return convert_optab_handler (optab, imode, vmode);
}
-/* Expand LOAD_LANES call STMT. */
+/* Expand LOAD_LANES call STMT using optab OPTAB. */
static void
-expand_LOAD_LANES (gcall *stmt)
+expand_load_lanes_optab_fn (gcall *stmt, convert_optab optab)
{
struct expand_operand ops[2];
tree type, lhs, rhs;
@@ -106,13 +118,13 @@ expand_LOAD_LANES (gcall *stmt)
create_output_operand (&ops[0], target, TYPE_MODE (type));
create_fixed_operand (&ops[1], mem);
- expand_insn (get_multi_vector_move (type, vec_load_lanes_optab), 2, ops);
+ expand_insn (get_multi_vector_move (type, optab), 2, ops);
}
-/* Expand STORE_LANES call STMT. */
+/* Expand STORE_LANES call STMT using optab OPTAB. */
static void
-expand_STORE_LANES (gcall *stmt)
+expand_store_lanes_optab_fn (gcall *stmt, convert_optab optab)
{
struct expand_operand ops[2];
tree type, lhs, rhs;
@@ -130,7 +142,7 @@ expand_STORE_LANES (gcall *stmt)
create_fixed_operand (&ops[0], target);
create_input_operand (&ops[1], reg, TYPE_MODE (type));
- expand_insn (get_multi_vector_move (type, vec_store_lanes_optab), 2, ops);
+ expand_insn (get_multi_vector_move (type, optab), 2, ops);
}
static void
@@ -1867,8 +1879,10 @@ expand_LOOP_VECTORIZED (gcall *)
gcc_unreachable ();
}
+/* Expand MASK_LOAD call STMT using optab OPTAB. */
+
static void
-expand_MASK_LOAD (gcall *stmt)
+expand_mask_load_optab_fn (gcall *stmt, convert_optab optab)
{
struct expand_operand ops[3];
tree type, lhs, rhs, maskt;
@@ -1889,13 +1903,15 @@ expand_MASK_LOAD (gcall *stmt)
create_output_operand (&ops[0], target, TYPE_MODE (type));
create_fixed_operand (&ops[1], mem);
create_input_operand (&ops[2], mask, TYPE_MODE (TREE_TYPE (maskt)));
- expand_insn (convert_optab_handler (maskload_optab, TYPE_MODE (type),
+ expand_insn (convert_optab_handler (optab, TYPE_MODE (type),
TYPE_MODE (TREE_TYPE (maskt))),
3, ops);
}
+/* Expand MASK_STORE call STMT using optab OPTAB. */
+
static void
-expand_MASK_STORE (gcall *stmt)
+expand_mask_store_optab_fn (gcall *stmt, convert_optab optab)
{
struct expand_operand ops[3];
tree type, lhs, rhs, maskt;
@@ -1914,7 +1930,7 @@ expand_MASK_STORE (gcall *stmt)
create_fixed_operand (&ops[0], mem);
create_input_operand (&ops[1], reg, TYPE_MODE (type));
create_input_operand (&ops[2], mask, TYPE_MODE (TREE_TYPE (maskt)));
- expand_insn (convert_optab_handler (maskstore_optab, TYPE_MODE (type),
+ expand_insn (convert_optab_handler (optab, TYPE_MODE (type),
TYPE_MODE (TREE_TYPE (maskt))),
3, ops);
}
@@ -2054,6 +2070,104 @@ expand_GOACC_REDUCTION (gcall *stmt ATTRIBUTE_UNUSED)
gcc_unreachable ();
}
+/* 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
+ target supports FN. */
+
+tree_pair
+direct_internal_fn_types (internal_fn fn, tree return_type, tree *args)
+{
+ const direct_internal_fn_info &info = direct_internal_fn (fn);
+ tree type0 = (info.type0 < 0 ? return_type : TREE_TYPE (args[info.type0]));
+ tree type1 = (info.type1 < 0 ? return_type : TREE_TYPE (args[info.type1]));
+ return tree_pair (type0, type1);
+}
+
+/* CALL is a call whose return type and arguments are in principle
+ compatible with FN (which satisfies direct_internal_fn_p). Return the
+ types that should be used to determine whether the target supports FN. */
+
+tree_pair
+direct_internal_fn_types (internal_fn fn, gcall *call)
+{
+ const direct_internal_fn_info &info = direct_internal_fn (fn);
+ tree op0 = (info.type0 < 0
+ ? gimple_call_lhs (call)
+ : gimple_call_arg (call, info.type0));
+ tree op1 = (info.type1 < 0
+ ? gimple_call_lhs (call)
+ : gimple_call_arg (call, info.type1));
+ return tree_pair (TREE_TYPE (op0), TREE_TYPE (op1));
+}
+
+/* Return true if OPTAB is supported for TYPES (whose modes should be
+ the same). Used for simple direct optabs. */
+
+static bool
+direct_optab_supported_p (direct_optab optab, tree_pair types)
+{
+ machine_mode mode = TYPE_MODE (types.first);
+ gcc_checking_assert (mode == TYPE_MODE (types.second));
+ return direct_optab_handler (optab, mode) != CODE_FOR_nothing;
+}
+
+/* Return true if load/store lanes optab OPTAB is supported for
+ array type TYPES.first. */
+
+static bool
+multi_vector_optab_supported_p (convert_optab optab, tree_pair types)
+{
+ return get_multi_vector_move (types.first, optab) != CODE_FOR_nothing;
+}
+
+#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
+#define direct_store_lanes_optab_supported_p multi_vector_optab_supported_p
+
+/* Return true if FN is supported for the types in TYPES. The types
+ are those associated with the "type0" and "type1" fields of FN's
+ direct_internal_fn_info structure. */
+
+bool
+direct_internal_fn_supported_p (internal_fn fn, tree_pair types)
+{
+ switch (fn)
+ {
+#define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
+ case IFN_##CODE: break;
+#define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
+ case IFN_##CODE: \
+ return direct_##TYPE##_optab_supported_p (OPTAB##_optab, types);
+#include "internal-fn.def"
+
+ case IFN_LAST:
+ break;
+ }
+ gcc_unreachable ();
+}
+
+/* Return true if FN is supported for type TYPE. The caller knows that
+ the "type0" and "type1" fields of FN's direct_internal_fn_info
+ structure are the same. */
+
+bool
+direct_internal_fn_supported_p (internal_fn fn, tree type)
+{
+ const direct_internal_fn_info &info = direct_internal_fn (fn);
+ gcc_checking_assert (info.type0 == info.type1);
+ return direct_internal_fn_supported_p (fn, tree_pair (type, type));
+}
+
+#define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
+ static void \
+ expand_##CODE (gcall *stmt) \
+ { \
+ expand_##TYPE##_optab_fn (stmt, OPTAB##_optab); \
+ }
+#include "internal-fn.def"
+
/* Routines to expand each internal function, indexed by function number.
Each routine has the prototype:
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index d0eb704..a5f6df2 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -26,29 +26,56 @@ along with GCC; see the file COPYING3. If not see
and its operands are more naturally represented as a GIMPLE_CALL
than a GIMPLE_ASSIGN.
- Each entry in this file has the form:
+ Each entry in this file has one of the forms:
DEF_INTERNAL_FN (NAME, FLAGS, FNSPEC)
+ DEF_INTERNAL_OPTAB_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.
+ DEF_INTERNAL_OPTAB_FN defines an internal function that maps to a
+ direct optab. The function should only be called with a given
+ set of types if the associated optab is available for the modes
+ of those types. OPTAB says what optab to use (without the trailing
+ "_optab") and TYPE categorizes the optab based on its inputs and
+ outputs. The possible types of optab are:
+
+ - mask_load: currently just maskload
+ - load_lanes: currently just vec_load_lanes
+
+ - mask_store: currently just maskstore
+ - store_lanes: currently just vec_store_lanes
+
Each entry must have a corresponding expander of the form:
void expand_NAME (gimple_call stmt)
- where STMT is the statement that performs the call. */
+ where STMT is the statement that performs the call. These are generated
+ automatically for optab functions and call out to a function or macro
+ called expand_<TYPE>_optab_fn. */
+
+#ifndef DEF_INTERNAL_FN
+#define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC)
+#endif
+
+#ifndef DEF_INTERNAL_OPTAB_FN
+#define DEF_INTERNAL_OPTAB_FN(NAME, FLAGS, OPTAB, TYPE) \
+ DEF_INTERNAL_FN (NAME, FLAGS | ECF_LEAF, NULL)
+#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)
-DEF_INTERNAL_FN (LOAD_LANES, ECF_CONST | ECF_LEAF, NULL)
-DEF_INTERNAL_FN (STORE_LANES, ECF_CONST | ECF_LEAF, NULL)
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)
DEF_INTERNAL_FN (GOMP_SIMD_ORDERED_START, ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (GOMP_SIMD_ORDERED_END, ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (LOOP_VECTORIZED, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
-DEF_INTERNAL_FN (MASK_LOAD, ECF_PURE | ECF_LEAF, NULL)
-DEF_INTERNAL_FN (MASK_STORE, ECF_LEAF, NULL)
DEF_INTERNAL_FN (ANNOTATE, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (UBSAN_NULL, ECF_LEAF | ECF_NOTHROW, ".R.")
DEF_INTERNAL_FN (UBSAN_BOUNDS, ECF_LEAF | ECF_NOTHROW, NULL)
@@ -87,4 +114,5 @@ 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_OPTAB_FN
#undef DEF_INTERNAL_FN
diff --git a/gcc/internal-fn.h b/gcc/internal-fn.h
index 20cbd13..31e895e 100644
--- a/gcc/internal-fn.h
+++ b/gcc/internal-fn.h
@@ -123,6 +123,44 @@ internal_fn_fnspec (enum internal_fn fn)
return internal_fn_fnspec_array[(int) fn];
}
+/* Describes an internal function that maps directly to an optab. */
+struct direct_internal_fn_info
+{
+ /* optabs can be parameterized by one or two modes. These fields describe
+ how to select those modes from the types of the return value and
+ arguments. A value of -1 says that the mode is determined by the
+ return type while a value N >= 0 says that the mode is determined by
+ the type of argument N. A value of -2 says that this internal
+ function isn't directly mapped to an optab. */
+ signed int type0 : 8;
+ signed int type1 : 8;
+};
+
+extern const direct_internal_fn_info direct_internal_fn_array[IFN_LAST + 1];
+
+/* Return true if FN is mapped directly to an optab. */
+
+inline bool
+direct_internal_fn_p (internal_fn fn)
+{
+ return direct_internal_fn_array[fn].type0 >= -1;
+}
+
+/* Return optab information about internal function FN. Only meaningful
+ if direct_internal_fn_p (FN). */
+
+inline const direct_internal_fn_info &
+direct_internal_fn (internal_fn fn)
+{
+ gcc_checking_assert (direct_internal_fn_p (fn));
+ return direct_internal_fn_array[fn];
+}
+
+extern tree_pair direct_internal_fn_types (internal_fn, tree, tree *);
+extern tree_pair direct_internal_fn_types (internal_fn, gcall *);
+extern bool direct_internal_fn_supported_p (internal_fn, tree_pair);
+extern bool direct_internal_fn_supported_p (internal_fn, tree);
+
extern void expand_internal_call (gcall *);
#endif