Add basic support for direct_optab internal functions
authorRichard Sandiford <richard.sandiford@arm.com>
Tue, 17 Nov 2015 18:37:45 +0000 (18:37 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Tue, 17 Nov 2015 18:37:45 +0000 (18:37 +0000)
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

gcc/ChangeLog
gcc/coretypes.h
gcc/internal-fn.c
gcc/internal-fn.def
gcc/internal-fn.h

index 74c7cf939d7deeb92c03444b1aef59cc46fd1c4b..bdb295c6f2463b01a4c1002eac451ca1473b9e68 100644 (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
index 3439c382cab63a447b92437acd57a25eed43c04c..d4a75db3b283c761741fd5e2585dc3afbdee2259 100644 (file)
@@ -251,6 +251,8 @@ namespace gcc {
   class context;
 }
 
+typedef std::pair <tree, tree> tree_pair;
+
 #else
 
 struct _dont_use_rtx_here_;
index 79425ea6a0ff4d5e2a1b225f33fe6caca790b34d..e77006d4dd317eede139fac7349b952b80ed43b2 100644 (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:
 
index d0eb704bd157db56bda31e911242215d7bd718ad..a5f6df26a91f57f71b922ff6e19edb567437c22d 100644 (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
index 20cbd13e4b669eab835d6e2a312aa2169fd56330..31e895ecd34a12182592debcce5e04a06b1e75d5 100644 (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