Add more subreg offset helpers
authorRichard Sandiford <richard.sandiford@arm.com>
Wed, 23 Nov 2016 14:31:13 +0000 (14:31 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Wed, 23 Nov 2016 14:31:13 +0000 (14:31 +0000)
Provide versions of subreg_lowpart_offset and subreg_highpart_offset
that work on mode sizes rather than modes.  Also provide a routine
that converts an lsb position to a subreg offset.

The intent (in combination with later patches) is to move the
handling of the BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN case into
just two places, so that for other combinations we don't have
to split offsets into words and subwords.

gcc/
2016-11-15  Richard Sandiford  <richard.sandiford@arm.com>
    Alan Hayward  <alan.hayward@arm.com>
    David Sherwood  <david.sherwood@arm.com>

* rtl.h (subreg_size_offset_from_lsb): Declare.
(subreg_offset_from_lsb): New function.
(subreg_size_lowpart_offset): Declare.
(subreg_lowpart_offset): Turn into an inline function.
(subreg_size_highpart_offset): Declare.
(subreg_highpart_offset): Turn into an inline function.
* emit-rtl.c (subreg_size_lowpart_offset): New function.
(subreg_size_highpart_offset): Likewise
* rtlanal.c (subreg_size_offset_from_lsb): Likewise.

Co-Authored-By: Alan Hayward <alan.hayward@arm.com>
Co-Authored-By: David Sherwood <david.sherwood@arm.com>
From-SVN: r242755

gcc/ChangeLog
gcc/emit-rtl.c
gcc/rtl.h
gcc/rtlanal.c

index bafdafbbbbc589b6a197fc36095ef56aa484fcd2..aa1d22f92d7b19449df3e965e13fe3fa5db91eda 100644 (file)
@@ -1,3 +1,17 @@
+2016-11-23  Richard Sandiford  <richard.sandiford@arm.com>
+           Alan Hayward  <alan.hayward@arm.com>
+           David Sherwood  <david.sherwood@arm.com>
+
+       * rtl.h (subreg_size_offset_from_lsb): Declare.
+       (subreg_offset_from_lsb): New function.
+       (subreg_size_lowpart_offset): Declare.
+       (subreg_lowpart_offset): Turn into an inline function.
+       (subreg_size_highpart_offset): Declare.
+       (subreg_highpart_offset): Turn into an inline function.
+       * emit-rtl.c (subreg_size_lowpart_offset): New function.
+       (subreg_size_highpart_offset): Likewise
+       * rtlanal.c (subreg_size_offset_from_lsb): Likewise.
+
 2016-11-23  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/78482
index 9ea0c8fb8881f04271fb8287aea8c716036f4a3f..04ce2d1398b0e249c4ff877963426f44a0a25da1 100644 (file)
@@ -1478,44 +1478,41 @@ gen_highpart_mode (machine_mode outermode, machine_mode innermode, rtx exp)
                              subreg_highpart_offset (outermode, innermode));
 }
 
-/* Return the SUBREG_BYTE for an OUTERMODE lowpart of an INNERMODE value.  */
+/* Return the SUBREG_BYTE for a lowpart subreg whose outer mode has
+   OUTER_BYTES bytes and whose inner mode has INNER_BYTES bytes.  */
 
 unsigned int
-subreg_lowpart_offset (machine_mode outermode, machine_mode innermode)
+subreg_size_lowpart_offset (unsigned int outer_bytes, unsigned int inner_bytes)
 {
-  unsigned int offset = 0;
-  int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
-
-  if (difference > 0)
-    {
-      if (WORDS_BIG_ENDIAN)
-       offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
-      if (BYTES_BIG_ENDIAN)
-       offset += difference % UNITS_PER_WORD;
-    }
+  if (outer_bytes > inner_bytes)
+    /* Paradoxical subregs always have a SUBREG_BYTE of 0.  */
+    return 0;
 
-  return offset;
+  if (BYTES_BIG_ENDIAN && WORDS_BIG_ENDIAN)
+    return inner_bytes - outer_bytes;
+  else if (!BYTES_BIG_ENDIAN && !WORDS_BIG_ENDIAN)
+    return 0;
+  else
+    return subreg_size_offset_from_lsb (outer_bytes, inner_bytes, 0);
 }
 
-/* Return offset in bytes to get OUTERMODE high part
-   of the value in mode INNERMODE stored in memory in target format.  */
+/* Return the SUBREG_BYTE for a highpart subreg whose outer mode has
+   OUTER_BYTES bytes and whose inner mode has INNER_BYTES bytes.  */
+
 unsigned int
-subreg_highpart_offset (machine_mode outermode, machine_mode innermode)
+subreg_size_highpart_offset (unsigned int outer_bytes,
+                            unsigned int inner_bytes)
 {
-  unsigned int offset = 0;
-  int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
+  gcc_assert (inner_bytes >= outer_bytes);
 
-  gcc_assert (GET_MODE_SIZE (innermode) >= GET_MODE_SIZE (outermode));
-
-  if (difference > 0)
-    {
-      if (! WORDS_BIG_ENDIAN)
-       offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
-      if (! BYTES_BIG_ENDIAN)
-       offset += difference % UNITS_PER_WORD;
-    }
-
-  return offset;
+  if (BYTES_BIG_ENDIAN && WORDS_BIG_ENDIAN)
+    return 0;
+  else if (!BYTES_BIG_ENDIAN && !WORDS_BIG_ENDIAN)
+    return inner_bytes - outer_bytes;
+  else
+    return subreg_size_offset_from_lsb (outer_bytes, inner_bytes,
+                                       (inner_bytes - outer_bytes)
+                                       * BITS_PER_UNIT);
 }
 
 /* Return 1 iff X, assumed to be a SUBREG,
index 21f48600deb69a1031df8e1990a10f264e73040f..660d381939da4cd22d06948c3b51c1993c892e73 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2178,6 +2178,24 @@ extern void get_full_rtx_cost (rtx, machine_mode, enum rtx_code, int,
 extern unsigned int subreg_lsb (const_rtx);
 extern unsigned int subreg_lsb_1 (machine_mode, machine_mode,
                                  unsigned int);
+extern unsigned int subreg_size_offset_from_lsb (unsigned int, unsigned int,
+                                                unsigned int);
+
+/* Return the subreg byte offset for a subreg whose outer mode is
+   OUTER_MODE, whose inner mode is INNER_MODE, and where there are
+   LSB_SHIFT *bits* between the lsb of the outer value and the lsb of
+   the inner value.  This is the inverse of subreg_lsb_1 (which converts
+   byte offsets to bit shifts).  */
+
+inline unsigned int
+subreg_offset_from_lsb (machine_mode outer_mode,
+                       machine_mode inner_mode,
+                       unsigned int lsb_shift)
+{
+  return subreg_size_offset_from_lsb (GET_MODE_SIZE (outer_mode),
+                                     GET_MODE_SIZE (inner_mode), lsb_shift);
+}
+
 extern unsigned int subreg_regno_offset        (unsigned int, machine_mode,
                                         unsigned int, machine_mode);
 extern bool subreg_offset_representable_p (unsigned int, machine_mode,
@@ -2764,10 +2782,28 @@ extern rtx operand_subword (rtx, unsigned int, int, machine_mode);
 extern rtx operand_subword_force (rtx, unsigned int, machine_mode);
 extern bool paradoxical_subreg_p (const_rtx);
 extern int subreg_lowpart_p (const_rtx);
-extern unsigned int subreg_lowpart_offset (machine_mode,
-                                          machine_mode);
-extern unsigned int subreg_highpart_offset (machine_mode,
-                                           machine_mode);
+extern unsigned int subreg_size_lowpart_offset (unsigned int, unsigned int);
+
+/* Return the SUBREG_BYTE for an OUTERMODE lowpart of an INNERMODE value.  */
+
+inline unsigned int
+subreg_lowpart_offset (machine_mode outermode, machine_mode innermode)
+{
+  return subreg_size_lowpart_offset (GET_MODE_SIZE (outermode),
+                                    GET_MODE_SIZE (innermode));
+}
+
+extern unsigned int subreg_size_highpart_offset (unsigned int, unsigned int);
+
+/* Return the SUBREG_BYTE for an OUTERMODE highpart of an INNERMODE value.  */
+
+inline unsigned int
+subreg_highpart_offset (machine_mode outermode, machine_mode innermode)
+{
+  return subreg_size_highpart_offset (GET_MODE_SIZE (outermode),
+                                     GET_MODE_SIZE (innermode));
+}
+
 extern int byte_lowpart_offset (machine_mode, machine_mode);
 extern rtx make_safe_from (rtx, rtx);
 extern rtx convert_memory_address_addr_space_1 (machine_mode, rtx,
index 7b8ff24fe345c237d1644310c7da60ea0fc7d8e9..d29a3fe75f7943f240d079013045398768a09c0b 100644 (file)
@@ -3528,6 +3528,42 @@ subreg_lsb (const_rtx x)
                       SUBREG_BYTE (x));
 }
 
+/* Return the subreg byte offset for a subreg whose outer value has
+   OUTER_BYTES bytes, whose inner value has INNER_BYTES bytes, and where
+   there are LSB_SHIFT *bits* between the lsb of the outer value and the
+   lsb of the inner value.  This is the inverse of the calculation
+   performed by subreg_lsb_1 (which converts byte offsets to bit shifts).  */
+
+unsigned int
+subreg_size_offset_from_lsb (unsigned int outer_bytes,
+                            unsigned int inner_bytes,
+                            unsigned int lsb_shift)
+{
+  /* A paradoxical subreg begins at bit position 0.  */
+  if (outer_bytes > inner_bytes)
+    {
+      gcc_checking_assert (lsb_shift == 0);
+      return 0;
+    }
+
+  gcc_assert (lsb_shift % BITS_PER_UNIT == 0);
+  unsigned int lower_bytes = lsb_shift / BITS_PER_UNIT;
+  unsigned int upper_bytes = inner_bytes - (lower_bytes + outer_bytes);
+  if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
+    return upper_bytes;
+  else if (!WORDS_BIG_ENDIAN && !BYTES_BIG_ENDIAN)
+    return lower_bytes;
+  else
+    {
+      unsigned int lower_word_part = lower_bytes & -UNITS_PER_WORD;
+      unsigned int upper_word_part = upper_bytes & -UNITS_PER_WORD;
+      if (WORDS_BIG_ENDIAN)
+       return upper_word_part + (lower_bytes - lower_word_part);
+      else
+       return lower_word_part + (upper_bytes - upper_word_part);
+    }
+}
+
 /* Fill in information about a subreg of a hard register.
    xregno - A regno of an inner hard subreg_reg (or what will become one).
    xmode  - The mode of xregno.