diff mbox series

Simplify & expand c_readstr

Message ID mpto7hms9lu.fsf@arm.com
State New
Headers show
Series Simplify & expand c_readstr | expand

Commit Message

Richard Sandiford Sept. 28, 2023, 1:36 p.m. UTC
c_readstr only operated on integer modes.  It worked by reading
the source string into an array of HOST_WIDE_INTs, converting
that array into a wide_int, and from there to an rtx.

It's simpler to do this by building a target memory image and
using native_decode_rtx to convert that memory image into an rtx.
It avoids all the endianness shenanigans because both the string and
native_decode_rtx follow target memory order.  It also means that the
function can handle all fixed-size modes, which simplifies callers
and allows vector modes to be used more widely.

Tested on aarch64-linux-gnu so far.  OK to install?

Richard


gcc/
	* builtins.h (c_readstr): Take a fixed_size_mode rather than a
	scalar_int_mode.
	* builtins.cc (c_readstr): Likewise.  Build a local array of
	bytes and use native_decode_rtx to get the rtx image.
	(builtin_memcpy_read_str): Simplify accordingly.
	(builtin_strncpy_read_str): Likewise.
	(builtin_memset_read_str): Likewise.
	(builtin_memset_gen_str: Likewise.
	* expr.cc (string_cst_read_str): Likewise.
---
 gcc/builtins.cc | 46 +++++++++++-----------------------------------
 gcc/builtins.h  |  2 +-
 gcc/expr.cc     |  5 ++---
 3 files changed, 14 insertions(+), 39 deletions(-)

Comments

Richard Biener Sept. 29, 2023, 6:28 a.m. UTC | #1
On Thu, Sep 28, 2023 at 3:37 PM Richard Sandiford
<richard.sandiford@arm.com> wrote:
>
> c_readstr only operated on integer modes.  It worked by reading
> the source string into an array of HOST_WIDE_INTs, converting
> that array into a wide_int, and from there to an rtx.
>
> It's simpler to do this by building a target memory image and
> using native_decode_rtx to convert that memory image into an rtx.
> It avoids all the endianness shenanigans because both the string and
> native_decode_rtx follow target memory order.  It also means that the
> function can handle all fixed-size modes, which simplifies callers
> and allows vector modes to be used more widely.
>
> Tested on aarch64-linux-gnu so far.  OK to install?

OK.

Richard.

> Richard
>
>
> gcc/
>         * builtins.h (c_readstr): Take a fixed_size_mode rather than a
>         scalar_int_mode.
>         * builtins.cc (c_readstr): Likewise.  Build a local array of
>         bytes and use native_decode_rtx to get the rtx image.
>         (builtin_memcpy_read_str): Simplify accordingly.
>         (builtin_strncpy_read_str): Likewise.
>         (builtin_memset_read_str): Likewise.
>         (builtin_memset_gen_str: Likewise.
>         * expr.cc (string_cst_read_str): Likewise.
> ---
>  gcc/builtins.cc | 46 +++++++++++-----------------------------------
>  gcc/builtins.h  |  2 +-
>  gcc/expr.cc     |  5 ++---
>  3 files changed, 14 insertions(+), 39 deletions(-)
>
> diff --git a/gcc/builtins.cc b/gcc/builtins.cc
> index 40dfd36a319..cb90bd03b3e 100644
> --- a/gcc/builtins.cc
> +++ b/gcc/builtins.cc
> @@ -743,39 +743,22 @@ c_strlen (tree arg, int only_value, c_strlen_data *data, unsigned eltsize)
>     as needed.  */
>
>  rtx
> -c_readstr (const char *str, scalar_int_mode mode,
> +c_readstr (const char *str, fixed_size_mode mode,
>            bool null_terminated_p/*=true*/)
>  {
> -  HOST_WIDE_INT ch;
> -  unsigned int i, j;
> -  HOST_WIDE_INT tmp[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
> +  auto_vec<target_unit, MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT> bytes;
>
> -  gcc_assert (GET_MODE_CLASS (mode) == MODE_INT);
> -  unsigned int len = (GET_MODE_PRECISION (mode) + HOST_BITS_PER_WIDE_INT - 1)
> -    / HOST_BITS_PER_WIDE_INT;
> +  bytes.reserve (GET_MODE_SIZE (mode));
>
> -  gcc_assert (len <= MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT);
> -  for (i = 0; i < len; i++)
> -    tmp[i] = 0;
> -
> -  ch = 1;
> -  for (i = 0; i < GET_MODE_SIZE (mode); i++)
> +  target_unit ch = 1;
> +  for (unsigned int i = 0; i < GET_MODE_SIZE (mode); ++i)
>      {
> -      j = i;
> -      if (WORDS_BIG_ENDIAN)
> -       j = GET_MODE_SIZE (mode) - i - 1;
> -      if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
> -         && GET_MODE_SIZE (mode) >= UNITS_PER_WORD)
> -       j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
> -      j *= BITS_PER_UNIT;
> -
>        if (ch || !null_terminated_p)
>         ch = (unsigned char) str[i];
> -      tmp[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
> +      bytes.quick_push (ch);
>      }
>
> -  wide_int c = wide_int::from_array (tmp, len, GET_MODE_PRECISION (mode));
> -  return immed_wide_int_const (c, mode);
> +  return native_decode_rtx (mode, bytes, 0);
>  }
>
>  /* Cast a target constant CST to target CHAR and if that value fits into
> @@ -3530,10 +3513,7 @@ builtin_memcpy_read_str (void *data, void *, HOST_WIDE_INT offset,
>       string but the caller guarantees it's large enough for MODE.  */
>    const char *rep = (const char *) data;
>
> -  /* The by-pieces infrastructure does not try to pick a vector mode
> -     for memcpy expansion.  */
> -  return c_readstr (rep + offset, as_a <scalar_int_mode> (mode),
> -                   /*nul_terminated=*/false);
> +  return c_readstr (rep + offset, mode, /*nul_terminated=*/false);
>  }
>
>  /* LEN specify length of the block of memcpy/memset operation.
> @@ -3994,9 +3974,7 @@ builtin_strncpy_read_str (void *data, void *, HOST_WIDE_INT offset,
>    if ((unsigned HOST_WIDE_INT) offset > strlen (str))
>      return const0_rtx;
>
> -  /* The by-pieces infrastructure does not try to pick a vector mode
> -     for strncpy expansion.  */
> -  return c_readstr (str + offset, as_a <scalar_int_mode> (mode));
> +  return c_readstr (str + offset, mode);
>  }
>
>  /* Helper to check the sizes of sequences and the destination of calls
> @@ -4227,8 +4205,7 @@ builtin_memset_read_str (void *data, void *prev,
>
>    memset (p, *c, size);
>
> -  /* Vector modes should be handled above.  */
> -  return c_readstr (p, as_a <scalar_int_mode> (mode));
> +  return c_readstr (p, mode);
>  }
>
>  /* Callback routine for store_by_pieces.  Return the RTL of a register
> @@ -4275,8 +4252,7 @@ builtin_memset_gen_str (void *data, void *prev,
>
>    p = XALLOCAVEC (char, size);
>    memset (p, 1, size);
> -  /* Vector modes should be handled above.  */
> -  coeff = c_readstr (p, as_a <scalar_int_mode> (mode));
> +  coeff = c_readstr (p, mode);
>
>    target = convert_to_mode (mode, (rtx) data, 1);
>    target = expand_mult (mode, target, coeff, NULL_RTX, 1);
> diff --git a/gcc/builtins.h b/gcc/builtins.h
> index 3b5c34c4802..88a26d70cd5 100644
> --- a/gcc/builtins.h
> +++ b/gcc/builtins.h
> @@ -105,7 +105,7 @@ struct c_strlen_data
>  };
>
>  extern tree c_strlen (tree, int, c_strlen_data * = NULL, unsigned = 1);
> -extern rtx c_readstr (const char *, scalar_int_mode, bool = true);
> +extern rtx c_readstr (const char *, fixed_size_mode, bool = true);
>  extern void expand_builtin_setjmp_setup (rtx, rtx);
>  extern void expand_builtin_setjmp_receiver (rtx);
>  extern void expand_builtin_update_setjmp_buf (rtx);
> diff --git a/gcc/expr.cc b/gcc/expr.cc
> index 308ddc09e63..a57948bdf01 100644
> --- a/gcc/expr.cc
> +++ b/gcc/expr.cc
> @@ -6083,13 +6083,12 @@ string_cst_read_str (void *data, void *, HOST_WIDE_INT offset,
>        size_t l = TREE_STRING_LENGTH (str) - offset;
>        memcpy (p, TREE_STRING_POINTER (str) + offset, l);
>        memset (p + l, '\0', GET_MODE_SIZE (mode) - l);
> -      return c_readstr (p, as_a <scalar_int_mode> (mode), false);
> +      return c_readstr (p, mode, false);
>      }
>
>    /* The by-pieces infrastructure does not try to pick a vector mode
>       for storing STRING_CST.  */
> -  return c_readstr (TREE_STRING_POINTER (str) + offset,
> -                   as_a <scalar_int_mode> (mode), false);
> +  return c_readstr (TREE_STRING_POINTER (str) + offset, mode, false);
>  }
>
>  /* Generate code for computing expression EXP,
> --
> 2.25.1
>
diff mbox series

Patch

diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 40dfd36a319..cb90bd03b3e 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -743,39 +743,22 @@  c_strlen (tree arg, int only_value, c_strlen_data *data, unsigned eltsize)
    as needed.  */
 
 rtx
-c_readstr (const char *str, scalar_int_mode mode,
+c_readstr (const char *str, fixed_size_mode mode,
 	   bool null_terminated_p/*=true*/)
 {
-  HOST_WIDE_INT ch;
-  unsigned int i, j;
-  HOST_WIDE_INT tmp[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+  auto_vec<target_unit, MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT> bytes;
 
-  gcc_assert (GET_MODE_CLASS (mode) == MODE_INT);
-  unsigned int len = (GET_MODE_PRECISION (mode) + HOST_BITS_PER_WIDE_INT - 1)
-    / HOST_BITS_PER_WIDE_INT;
+  bytes.reserve (GET_MODE_SIZE (mode));
 
-  gcc_assert (len <= MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT);
-  for (i = 0; i < len; i++)
-    tmp[i] = 0;
-
-  ch = 1;
-  for (i = 0; i < GET_MODE_SIZE (mode); i++)
+  target_unit ch = 1;
+  for (unsigned int i = 0; i < GET_MODE_SIZE (mode); ++i)
     {
-      j = i;
-      if (WORDS_BIG_ENDIAN)
-	j = GET_MODE_SIZE (mode) - i - 1;
-      if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
-	  && GET_MODE_SIZE (mode) >= UNITS_PER_WORD)
-	j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
-      j *= BITS_PER_UNIT;
-
       if (ch || !null_terminated_p)
 	ch = (unsigned char) str[i];
-      tmp[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
+      bytes.quick_push (ch);
     }
 
-  wide_int c = wide_int::from_array (tmp, len, GET_MODE_PRECISION (mode));
-  return immed_wide_int_const (c, mode);
+  return native_decode_rtx (mode, bytes, 0);
 }
 
 /* Cast a target constant CST to target CHAR and if that value fits into
@@ -3530,10 +3513,7 @@  builtin_memcpy_read_str (void *data, void *, HOST_WIDE_INT offset,
      string but the caller guarantees it's large enough for MODE.  */
   const char *rep = (const char *) data;
 
-  /* The by-pieces infrastructure does not try to pick a vector mode
-     for memcpy expansion.  */
-  return c_readstr (rep + offset, as_a <scalar_int_mode> (mode),
-		    /*nul_terminated=*/false);
+  return c_readstr (rep + offset, mode, /*nul_terminated=*/false);
 }
 
 /* LEN specify length of the block of memcpy/memset operation.
@@ -3994,9 +3974,7 @@  builtin_strncpy_read_str (void *data, void *, HOST_WIDE_INT offset,
   if ((unsigned HOST_WIDE_INT) offset > strlen (str))
     return const0_rtx;
 
-  /* The by-pieces infrastructure does not try to pick a vector mode
-     for strncpy expansion.  */
-  return c_readstr (str + offset, as_a <scalar_int_mode> (mode));
+  return c_readstr (str + offset, mode);
 }
 
 /* Helper to check the sizes of sequences and the destination of calls
@@ -4227,8 +4205,7 @@  builtin_memset_read_str (void *data, void *prev,
 
   memset (p, *c, size);
 
-  /* Vector modes should be handled above.  */
-  return c_readstr (p, as_a <scalar_int_mode> (mode));
+  return c_readstr (p, mode);
 }
 
 /* Callback routine for store_by_pieces.  Return the RTL of a register
@@ -4275,8 +4252,7 @@  builtin_memset_gen_str (void *data, void *prev,
 
   p = XALLOCAVEC (char, size);
   memset (p, 1, size);
-  /* Vector modes should be handled above.  */
-  coeff = c_readstr (p, as_a <scalar_int_mode> (mode));
+  coeff = c_readstr (p, mode);
 
   target = convert_to_mode (mode, (rtx) data, 1);
   target = expand_mult (mode, target, coeff, NULL_RTX, 1);
diff --git a/gcc/builtins.h b/gcc/builtins.h
index 3b5c34c4802..88a26d70cd5 100644
--- a/gcc/builtins.h
+++ b/gcc/builtins.h
@@ -105,7 +105,7 @@  struct c_strlen_data
 };
 
 extern tree c_strlen (tree, int, c_strlen_data * = NULL, unsigned = 1);
-extern rtx c_readstr (const char *, scalar_int_mode, bool = true);
+extern rtx c_readstr (const char *, fixed_size_mode, bool = true);
 extern void expand_builtin_setjmp_setup (rtx, rtx);
 extern void expand_builtin_setjmp_receiver (rtx);
 extern void expand_builtin_update_setjmp_buf (rtx);
diff --git a/gcc/expr.cc b/gcc/expr.cc
index 308ddc09e63..a57948bdf01 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -6083,13 +6083,12 @@  string_cst_read_str (void *data, void *, HOST_WIDE_INT offset,
       size_t l = TREE_STRING_LENGTH (str) - offset;
       memcpy (p, TREE_STRING_POINTER (str) + offset, l);
       memset (p + l, '\0', GET_MODE_SIZE (mode) - l);
-      return c_readstr (p, as_a <scalar_int_mode> (mode), false);
+      return c_readstr (p, mode, false);
     }
 
   /* The by-pieces infrastructure does not try to pick a vector mode
      for storing STRING_CST.  */
-  return c_readstr (TREE_STRING_POINTER (str) + offset,
-		    as_a <scalar_int_mode> (mode), false);
+  return c_readstr (TREE_STRING_POINTER (str) + offset, mode, false);
 }
 
 /* Generate code for computing expression EXP,