]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/arm/arm-mve-builtins.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / config / arm / arm-mve-builtins.cc
index 7c34d2a94de4fdca84eb57fd7f51620918597e7e..c533d0e93ae3f8df8820506befbaa0254192ea17 100644 (file)
@@ -1,5 +1,5 @@
 /* ACLE support for Arm MVE
-   Copyright (C) 2021-2023 Free Software Foundation, Inc.
+   Copyright (C) 2021-2024 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -36,6 +36,7 @@
 #include "fold-const.h"
 #include "gimple.h"
 #include "gimple-iterator.h"
+#include "explow.h"
 #include "emit-rtl.h"
 #include "langhooks.h"
 #include "stringpool.h"
@@ -128,10 +129,11 @@ CONSTEXPR const type_suffix_info type_suffixes[NUM_TYPE_SUFFIXES + 1] = {
     TYPE_##CLASS == TYPE_signed || TYPE_##CLASS == TYPE_unsigned, \
     TYPE_##CLASS == TYPE_unsigned, \
     TYPE_##CLASS == TYPE_float, \
+    TYPE_##CLASS == TYPE_poly, \
     0, \
     MODE },
 #include "arm-mve-builtins.def"
-  { "", NUM_VECTOR_TYPES, TYPE_bool, 0, 0, false, false, false,
+  { "", NUM_VECTOR_TYPES, TYPE_bool, 0, 0, false, false, false, false,
     0, VOIDmode }
 };
 
@@ -177,6 +179,10 @@ CONSTEXPR const type_suffix_info type_suffixes[NUM_TYPE_SUFFIXES + 1] = {
 #define TYPES_all_signed(S, D) \
   S (s8), S (s16), S (s32)
 
+/* _p8 _p16.  */
+#define TYPES_poly_8_16(S, D) \
+  S (p8), S (p16)
+
 /* _u8 _u16 _u32.  */
 #define TYPES_all_unsigned(S, D) \
   S (u8), S (u16), S (u32)
@@ -275,6 +281,7 @@ DEF_MVE_TYPES_ARRAY (integer_8);
 DEF_MVE_TYPES_ARRAY (integer_8_16);
 DEF_MVE_TYPES_ARRAY (integer_16_32);
 DEF_MVE_TYPES_ARRAY (integer_32);
+DEF_MVE_TYPES_ARRAY (poly_8_16);
 DEF_MVE_TYPES_ARRAY (signed_16_32);
 DEF_MVE_TYPES_ARRAY (signed_32);
 DEF_MVE_TYPES_ARRAY (reinterpret_integer);
@@ -493,6 +500,16 @@ handle_arm_mve_h (bool preserve_user_namespace)
                                     preserve_user_namespace);
 }
 
+/* Return the function decl with MVE function subcode CODE, or error_mark_node
+   if no such function exists.  */
+tree
+builtin_decl (unsigned int code)
+{
+  if (code >= vec_safe_length (registered_functions))
+    return error_mark_node;
+  return (*registered_functions)[code]->decl;
+}
+
 /* Return true if CANDIDATE is equivalent to MODEL_TYPE for overloading
    purposes.  */
 static bool
@@ -513,6 +530,22 @@ matches_type_p (const_tree model_type, const_tree candidate)
          && TYPE_MAIN_VARIANT (model_type) == TYPE_MAIN_VARIANT (candidate));
 }
 
+/* If TYPE is a valid MVE element type, return the corresponding type
+   suffix, otherwise return NUM_TYPE_SUFFIXES.  */
+static type_suffix_index
+find_type_suffix_for_scalar_type (const_tree type)
+{
+  /* A linear search should be OK here, since the code isn't hot and
+     the number of types is only small.  */
+  for (unsigned int suffix_i = 0; suffix_i < NUM_TYPE_SUFFIXES; ++suffix_i)
+      {
+       vector_type_index vector_i = type_suffixes[suffix_i].vector_type;
+       if (matches_type_p (scalar_types[vector_i], type))
+         return type_suffix_index (suffix_i);
+      }
+  return NUM_TYPE_SUFFIXES;
+}
+
 /* Report an error against LOCATION that the user has tried to use
    a floating point function when the mve.fp extension is disabled.  */
 static void
@@ -670,7 +703,46 @@ function_instance::has_inactive_argument () const
     return false;
 
   if (mode_suffix_id == MODE_r
+      || base == functions::vcmlaq
+      || base == functions::vcmlaq_rot90
+      || base == functions::vcmlaq_rot180
+      || base == functions::vcmlaq_rot270
+      || base == functions::vcmpeqq
+      || base == functions::vcmpneq
+      || base == functions::vcmpgeq
+      || base == functions::vcmpgtq
+      || base == functions::vcmpleq
+      || base == functions::vcmpltq
+      || base == functions::vcmpcsq
+      || base == functions::vcmphiq
+      || base == functions::vfmaq
+      || base == functions::vfmasq
+      || base == functions::vfmsq
+      || base == functions::vmaxaq
+      || base == functions::vmaxnmaq
+      || base == functions::vminaq
+      || base == functions::vminnmaq
+      || base == functions::vmlaq
+      || base == functions::vmlasq
+      || base == functions::vmovnbq
+      || base == functions::vmovntq
+      || base == functions::vqmovnbq
+      || base == functions::vqmovntq
+      || base == functions::vqmovunbq
+      || base == functions::vqmovuntq
       || (base == functions::vorrq && mode_suffix_id == MODE_n)
+      || base == functions::vqdmladhq
+      || base == functions::vqdmladhxq
+      || base == functions::vqdmlahq
+      || base == functions::vqdmlashq
+      || base == functions::vqdmlsdhq
+      || base == functions::vqdmlsdhxq
+      || base == functions::vqrdmladhq
+      || base == functions::vqrdmladhxq
+      || base == functions::vqrdmlahq
+      || base == functions::vqrdmlashq
+      || base == functions::vqrdmlsdhq
+      || base == functions::vqrdmlsdhxq
       || (base == functions::vqrshlq && mode_suffix_id == MODE_n)
       || base == functions::vqrshrnbq
       || base == functions::vqrshrntq
@@ -684,7 +756,9 @@ function_instance::has_inactive_argument () const
       || base == functions::vrshrnbq
       || base == functions::vrshrntq
       || base == functions::vshrnbq
-      || base == functions::vshrntq)
+      || base == functions::vshrntq
+      || base == functions::vsliq
+      || base == functions::vsriq)
     return false;
 
   return true;
@@ -812,7 +886,6 @@ function_builder::add_function (const function_instance &instance,
     ? integer_zero_node
     : simulate_builtin_function_decl (input_location, name, fntype,
                                      code, NULL, attrs);
-
   registered_function &rfn = *ggc_alloc <registered_function> ();
   rfn.instance = instance;
   rfn.decl = decl;
@@ -852,15 +925,12 @@ function_builder::add_unique_function (const function_instance &instance,
   gcc_assert (!*rfn_slot);
   *rfn_slot = &rfn;
 
-  /* Also add the non-prefixed non-overloaded function, if the user namespace
-     does not need to be preserved.  */
-  if (!preserve_user_namespace)
-    {
-      char *noprefix_name = get_name (instance, false, false);
-      tree attrs = get_attributes (instance);
-      add_function (instance, noprefix_name, fntype, attrs, requires_float,
-                   false, false);
-    }
+  /* Also add the non-prefixed non-overloaded function, as placeholder
+     if the user namespace does not need to be preserved.  */
+  char *noprefix_name = get_name (instance, false, false);
+  attrs = get_attributes (instance);
+  add_function (instance, noprefix_name, fntype, attrs, requires_float,
+               false, preserve_user_namespace);
 
   /* Also add the function under its overloaded alias, if we want
      a separate decl for each instance of an overloaded function.  */
@@ -868,20 +938,17 @@ function_builder::add_unique_function (const function_instance &instance,
   if (strcmp (name, overload_name) != 0)
     {
       /* Attribute lists shouldn't be shared.  */
-      tree attrs = get_attributes (instance);
+      attrs = get_attributes (instance);
       bool placeholder_p = !(m_direct_overloads || force_direct_overloads);
       add_function (instance, overload_name, fntype, attrs,
                    requires_float, false, placeholder_p);
 
-      /* Also add the non-prefixed overloaded function, if the user namespace
-        does not need to be preserved.  */
-      if (!preserve_user_namespace)
-       {
-         char *noprefix_overload_name = get_name (instance, false, true);
-         tree attrs = get_attributes (instance);
-         add_function (instance, noprefix_overload_name, fntype, attrs,
-                       requires_float, false, placeholder_p);
-       }
+      /* Also add the non-prefixed overloaded function, as placeholder
+        if the user namespace does not need to be preserved.  */
+      char *noprefix_overload_name = get_name (instance, false, true);
+      attrs = get_attributes (instance);
+      add_function (instance, noprefix_overload_name, fntype, attrs,
+                   requires_float, false, preserve_user_namespace || placeholder_p);
     }
 
   obstack_free (&m_string_obstack, name);
@@ -911,15 +978,15 @@ function_builder::add_overloaded_function (const function_instance &instance,
        = add_function (instance, name, m_overload_type, NULL_TREE,
                        requires_float, true, m_direct_overloads);
       m_overload_names.put (name, &rfn);
-      if (!preserve_user_namespace)
-       {
-         char *noprefix_name = get_name (instance, false, true);
-         registered_function &noprefix_rfn
-           = add_function (instance, noprefix_name, m_overload_type,
-                           NULL_TREE, requires_float, true,
-                           m_direct_overloads);
-         m_overload_names.put (noprefix_name, &noprefix_rfn);
-       }
+
+      /* Also add the non-prefixed function, as placeholder if the
+        user namespace does not need to be preserved.  */
+      char *noprefix_name = get_name (instance, false, true);
+      registered_function &noprefix_rfn
+       = add_function (instance, noprefix_name, m_overload_type,
+                       NULL_TREE, requires_float, true,
+                       preserve_user_namespace || m_direct_overloads);
+      m_overload_names.put (noprefix_name, &noprefix_rfn);
     }
 }
 
@@ -1075,6 +1142,36 @@ function_resolver::resolve_to (mode_suffix_index mode,
   return res;
 }
 
+/* Require argument ARGNO to be a pointer to a scalar type that has a
+   corresponding type suffix.  Return that type suffix on success,
+   otherwise report an error and return NUM_TYPE_SUFFIXES.  */
+type_suffix_index
+function_resolver::infer_pointer_type (unsigned int argno)
+{
+  tree actual = get_argument_type (argno);
+  if (actual == error_mark_node)
+    return NUM_TYPE_SUFFIXES;
+
+  if (TREE_CODE (actual) != POINTER_TYPE)
+    {
+      error_at (location, "passing %qT to argument %d of %qE, which"
+               " expects a pointer type", actual, argno + 1, fndecl);
+      return NUM_TYPE_SUFFIXES;
+    }
+
+  tree target = TREE_TYPE (actual);
+  type_suffix_index type = find_type_suffix_for_scalar_type (target);
+  if (type == NUM_TYPE_SUFFIXES)
+    {
+      error_at (location, "passing %qT to argument %d of %qE, but %qT is not"
+               " a valid MVE element type", actual, argno + 1, fndecl,
+               build_qualified_type (target, 0));
+      return NUM_TYPE_SUFFIXES;
+    }
+
+  return type;
+}
+
 /* Require argument ARGNO to be a single vector or a tuple of NUM_VECTORS
    vectors; NUM_VECTORS is 1 for the former.  Return the associated type
    suffix on success, using TYPE_SUFFIX_b for predicates.  Report an error
@@ -1448,6 +1545,22 @@ function_resolver::require_scalar_type (unsigned int argno,
   return true;
 }
 
+/* Require argument ARGNO to be some form of pointer, without being specific
+   about its target type.  Return true if the argument has the right form,
+   otherwise report an appropriate error.  */
+bool
+function_resolver::require_pointer_type (unsigned int argno)
+{
+  if (!scalar_argument_p (argno))
+    {
+      error_at (location, "passing %qT to argument %d of %qE, which"
+               " expects a scalar pointer", get_argument_type (argno),
+               argno + 1, fndecl);
+      return false;
+    }
+  return true;
+}
+
 /* Require the function to have exactly EXPECTED arguments.  Return true
    if it does, otherwise report an appropriate error.  */
 bool
@@ -1905,6 +2018,14 @@ function_expander::direct_optab_handler (optab op, unsigned int suffix_i)
   return ::direct_optab_handler (op, vector_mode (suffix_i));
 }
 
+/* Return the base address for a contiguous load or store
+   function.  */
+rtx
+function_expander::get_contiguous_base ()
+{
+  return args[0];
+}
+
 /* For a function that does the equivalent of:
 
      OUTPUT = COND ? FN (INPUTS) : FALLBACK;
@@ -1993,6 +2114,26 @@ function_expander::add_integer_operand (HOST_WIDE_INT x)
   create_integer_operand (&m_ops.last (), x);
 }
 
+/* Add a memory operand with mode MODE and address ADDR.  */
+void
+function_expander::add_mem_operand (machine_mode mode, rtx addr)
+{
+  gcc_assert (VECTOR_MODE_P (mode));
+  rtx mem = gen_rtx_MEM (mode, memory_address (mode, addr));
+  /* The memory is only guaranteed to be element-aligned.  */
+  set_mem_align (mem, GET_MODE_ALIGNMENT (GET_MODE_INNER (mode)));
+  add_fixed_operand (mem);
+}
+
+/* Add an operand that must be X.  The only way of legitimizing an
+   invalid X is to reload the address of a MEM.  */
+void
+function_expander::add_fixed_operand (rtx x)
+{
+  m_ops.safe_grow (m_ops.length () + 1, true);
+  create_fixed_operand (&m_ops.last (), x);
+}
+
 /* Generate instruction ICODE, given that its operands have already
    been added to M_OPS.  Return the value of the first operand.  */
 rtx
@@ -2087,6 +2228,30 @@ function_expander::use_cond_insn (insn_code icode, unsigned int merge_argno)
   return generate_insn (icode);
 }
 
+/* Implement the call using instruction ICODE, which loads memory operand 1
+   into register operand 0.  */
+rtx
+function_expander::use_contiguous_load_insn (insn_code icode)
+{
+  machine_mode mem_mode = memory_vector_mode ();
+
+  add_output_operand (icode);
+  add_mem_operand (mem_mode, get_contiguous_base ());
+  return generate_insn (icode);
+}
+
+/* Implement the call using instruction ICODE, which stores register operand 1
+   into memory operand 0.  */
+rtx
+function_expander::use_contiguous_store_insn (insn_code icode)
+{
+  machine_mode mem_mode = memory_vector_mode ();
+
+  add_mem_operand (mem_mode, get_contiguous_base ());
+  add_input_operand (icode, args[1]);
+  return generate_insn (icode);
+}
+
 /* Implement the call using a normal unpredicated optab for PRED_none.
 
    <optab> corresponds to: