https://gcc.gnu.org/g:c0ab34339836b779ea161f54cb3bb397cdbc6f10

commit r15-6229-gc0ab34339836b779ea161f54cb3bb397cdbc6f10
Author: Christophe Lyon <christophe.l...@linaro.org>
Date:   Mon Nov 4 21:41:47 2024 +0000

    arm: [MVE intrinsics] Check immediate is a multiple in a range
    
    This patch adds support to check that an immediate is a multiple of a
    given value in a given range.
    
    This will be used for instance by scatter_base to check that offset is
    in +/-4*[0..127].
    
    Unlike require_immediate_range, require_immediate_range_multiple
    accepts signed range bounds to handle the above case.
    
    gcc/ChangeLog:
    
            * config/arm/arm-mve-builtins.cc (report_out_of_range_multiple):
            New.
            (function_checker::require_signed_immediate): New.
            (function_checker::require_immediate_range_multiple): New.
            * config/arm/arm-mve-builtins.h
            (function_checker::require_immediate_range_multiple): New.
            (function_checker::require_signed_immediate): New.

Diff:
---
 gcc/config/arm/arm-mve-builtins.cc | 60 ++++++++++++++++++++++++++++++++++++++
 gcc/config/arm/arm-mve-builtins.h  |  3 ++
 2 files changed, 63 insertions(+)

diff --git a/gcc/config/arm/arm-mve-builtins.cc 
b/gcc/config/arm/arm-mve-builtins.cc
index 8e6fff089c42..b050e2630892 100644
--- a/gcc/config/arm/arm-mve-builtins.cc
+++ b/gcc/config/arm/arm-mve-builtins.cc
@@ -639,6 +639,20 @@ report_out_of_range (location_t location, tree fndecl, 
unsigned int argno,
            min, max);
 }
 
+/* Report that LOCATION has a call to FNDECL in which argument ARGNO has the
+   value ACTUAL, whereas the function requires a value multiple of MULT in the
+   range [MIN, MAX].  ARGNO counts from zero.  */
+static void
+report_out_of_range_multiple (location_t location, tree fndecl,
+                             unsigned int argno,
+                             HOST_WIDE_INT actual, HOST_WIDE_INT min,
+                             HOST_WIDE_INT max, HOST_WIDE_INT mult)
+{
+  error_at (location, "passing %wd to argument %d of %qE, which expects"
+           " a value multiple of %wd in the range [%wd, %wd]", actual,
+           argno + 1, fndecl, mult, min, max);
+}
+
 /* Report that LOCATION has a call to FNDECL in which argument ARGNO has
    the value ACTUAL, whereas the function requires a valid value of
    enum type ENUMTYPE.  ARGNO counts from zero.  */
@@ -1983,6 +1997,26 @@ function_checker::require_immediate (unsigned int argno,
   return true;
 }
 
+/* Check that argument ARGNO is a signed integer constant expression and store
+   its value in VALUE_OUT if so.  The caller should first check that argument
+   ARGNO exists.  */
+bool
+function_checker::require_signed_immediate (unsigned int argno,
+                                           HOST_WIDE_INT &value_out)
+{
+  gcc_assert (argno < m_nargs);
+  tree arg = m_args[argno];
+
+  if (!tree_fits_shwi_p (arg))
+    {
+      report_non_ice (location, fndecl, argno);
+      return false;
+    }
+
+  value_out = tree_to_shwi (arg);
+  return true;
+}
+
 /* Check that argument REL_ARGNO is an integer constant expression that has
    a valid value for enumeration type TYPE.  REL_ARGNO counts from the end
    of the predication arguments.  */
@@ -2070,6 +2104,32 @@ function_checker::require_immediate_range (unsigned int 
rel_argno,
   return true;
 }
 
+/* Check that argument REL_ARGNO is a signed integer constant expression in the
+   range [MIN, MAX].  Also check that REL_ARGNO is a multiple of MULT.  */
+bool
+function_checker::require_immediate_range_multiple (unsigned int rel_argno,
+                                                   HOST_WIDE_INT min,
+                                                   HOST_WIDE_INT max,
+                                                   HOST_WIDE_INT mult)
+{
+  unsigned int argno = m_base_arg + rel_argno;
+  if (!argument_exists_p (argno))
+    return true;
+
+  HOST_WIDE_INT actual;
+  if (!require_signed_immediate (argno, actual))
+    return false;
+
+  if (!IN_RANGE (actual, min, max)
+      || (actual % mult) != 0)
+    {
+      report_out_of_range_multiple (location, fndecl, argno, actual, min, max, 
mult);
+      return false;
+    }
+
+  return true;
+}
+
 /* Perform semantic checks on the call.  Return true if the call is valid,
    otherwise report a suitable error.  */
 bool
diff --git a/gcc/config/arm/arm-mve-builtins.h 
b/gcc/config/arm/arm-mve-builtins.h
index 3e0796f7c09c..5a191b0cde3c 100644
--- a/gcc/config/arm/arm-mve-builtins.h
+++ b/gcc/config/arm/arm-mve-builtins.h
@@ -436,6 +436,8 @@ public:
   bool require_immediate_one_of (unsigned int, HOST_WIDE_INT, HOST_WIDE_INT,
                                 HOST_WIDE_INT, HOST_WIDE_INT);
   bool require_immediate_range (unsigned int, HOST_WIDE_INT, HOST_WIDE_INT);
+  bool require_immediate_range_multiple (unsigned int, HOST_WIDE_INT,
+                                        HOST_WIDE_INT, HOST_WIDE_INT);
 
   bool check ();
 
@@ -443,6 +445,7 @@ private:
   bool argument_exists_p (unsigned int);
 
   bool require_immediate (unsigned int, HOST_WIDE_INT &);
+  bool require_signed_immediate (unsigned int, HOST_WIDE_INT &);
 
   /* The type of the resolved function.  */
   tree m_fntype;

Reply via email to