Add basic support for direct_optab internal functions

This patch adds a concept of internal functions that map directly to an
optab (here called "direct internal functions").  The function can only
be used if the associated optab can be used.

We currently have four functions like that:

- LOAD_LANES
- STORE_LANES
- MASK_LOAD
- MASK_STORE

so the patch converts them to the new infrastructure.  These four
all need different types of optabs, but future patches will add
regular unary and binary ones.

In general we need one or two modes to decide whether an optab is
supported, depending on whether it's a convert_optab or not.
This in turn means that we need up to two types to decide whether
an internal function is supported.  The patch records which types
are needed for each internal function, using -1 if the return type
should be used and N>=0 if the type of argument N should be used.

(LOAD_LANES and STORE_LANES are unusual in that both optab modes
come from the same array type.)

Tested on x86_64-linux-gnu, aarch64-linux-gnu and arm-linux-gnueabi.

gcc/
	* 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.

From-SVN: r230473
This commit is contained in:
Richard Sandiford 2015-11-17 18:37:45 +00:00 committed by Richard Sandiford
parent 00175cb22a
commit ab23f5d974
5 changed files with 233 additions and 21 deletions

View File

@ -1,3 +1,33 @@
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

View File

@ -251,6 +251,8 @@ namespace gcc {
class context;
}
typedef std::pair <tree, tree> tree_pair;
#else
struct _dont_use_rtx_here_;

View File

@ -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:

View File

@ -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

View File

@ -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