+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
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;
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;
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;
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
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;
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;
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);
}
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:
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)
/* 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