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]

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.
OK to install?

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]