This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Add basic support for direct_optab internal functions


On Sat, Nov 7, 2015 at 1:26 PM, Richard Sandiford
<richard.sandiford@arm.com> wrote:
> 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.
> OK to install?

Ok.

Thanks,
Richard.

> Thanks,
> Richard
>
>
> 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.
>
> 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 afbfae8..72536da 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, -1 }
> +#define load_lanes_direct { -1, -1 }
> +#define mask_store_direct { 3, 3 }
> +#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, direct_optab optab)
>  {
>    struct expand_operand ops[3];
>    tree type, lhs, rhs, maskt;
> @@ -1889,11 +1903,13 @@ 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 (optab_handler (maskload_optab, TYPE_MODE (type)), 3, ops);
> +  expand_insn (optab_handler (optab, TYPE_MODE (type)), 3, ops);
>  }
>
> +/* Expand MASK_STORE call STMT using optab OPTAB.  */
> +
>  static void
> -expand_MASK_STORE (gcall *stmt)
> +expand_mask_store_optab_fn (gcall *stmt, direct_optab optab)
>  {
>    struct expand_operand ops[3];
>    tree type, lhs, rhs, maskt;
> @@ -1912,7 +1928,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 (optab_handler (maskstore_optab, TYPE_MODE (type)), 3, ops);
> +  expand_insn (optab_handler (optab, TYPE_MODE (type)), 3, ops);
>  }
>
>  static void
> @@ -2050,6 +2066,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
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]