During the base register initialization, in the case that we are
eliminating the load instruction, we are using `offset == 0` in order
to find the store instruction that has the same offset as the load. This
would not work on big-endian targets where byte 0 would be the MS byte.

This patch updates the condition to take into account the target's endianness.

We are, also, removing the adjustment of the starting position for the
bitfield insertion, when BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN. This is
supposed to be handled inside `store_bit_field` and it's not needed anymore
after the offset fix.

Bootstrapped/regtested on AArch64 LE, x86_64 and PowerPC LE.

gcc/ChangeLog:

        * avoid-store-forwarding.cc (generate_bit_insert_sequence):
        Remove adjustment of bitfield insertion's starting position
        when BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN.
        * avoid-store-forwarding.cc (process_store_forwarding):
        Update offset check in base reg initialization to take
        into account the target's endianness.

gcc/testsuite/ChangeLog:

        * gcc.target/aarch64/avoid-store-forwarding-be.c: New test.
---
 gcc/avoid-store-forwarding.cc                 | 18 ++++-----------
 .../aarch64/avoid-store-forwarding-be.c       | 23 +++++++++++++++++++
 2 files changed, 28 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/avoid-store-forwarding-be.c

diff --git a/gcc/avoid-store-forwarding.cc b/gcc/avoid-store-forwarding.cc
index 37e095316c93..785efd22606f 100644
--- a/gcc/avoid-store-forwarding.cc
+++ b/gcc/avoid-store-forwarding.cc
@@ -119,17 +119,6 @@ generate_bit_insert_sequence (store_fwd_info *store_info, 
rtx dest)
   unsigned HOST_WIDE_INT bitsize = store_size * BITS_PER_UNIT;
   unsigned HOST_WIDE_INT start = store_info->offset * BITS_PER_UNIT;
 
-  /* Adjust START for machines with BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN.
-     Given that the bytes will be reversed in this case, we need to
-     calculate the starting position from the end of the destination
-     register.  */
-  if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
-    {
-      unsigned HOST_WIDE_INT load_mode_bitsize
-       = (GET_MODE_BITSIZE (GET_MODE (dest))).to_constant ();
-      start = load_mode_bitsize - bitsize - start;
-    }
-
   rtx mov_reg = store_info->mov_reg;
   store_bit_field (dest, bitsize, start, 0, 0, GET_MODE (mov_reg), mov_reg,
                   false, false);
@@ -248,11 +237,14 @@ process_store_forwarding (vec<store_fwd_info> &stores, 
rtx_insn *load_insn,
     {
       it->mov_reg = gen_reg_rtx (GET_MODE (it->store_mem));
       rtx_insn *insns = NULL;
-      const bool has_zero_offset = it->offset == 0;
+      const bool has_base_offset
+       = known_eq (poly_uint64 (it->offset),
+                   subreg_size_lowpart_offset (MEM_SIZE (it->store_mem),
+                                               load_size));
 
       /* If we're eliminating the load then find the store with zero offset
         and use it as the base register to avoid a bit insert if possible.  */
-      if (load_elim && has_zero_offset)
+      if (load_elim && has_base_offset)
        {
          start_sequence ();
 
diff --git a/gcc/testsuite/gcc.target/aarch64/avoid-store-forwarding-be.c 
b/gcc/testsuite/gcc.target/aarch64/avoid-store-forwarding-be.c
new file mode 100644
index 000000000000..2e8946b25e34
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/avoid-store-forwarding-be.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-require-effective-target aarch64_big_endian } */
+/* { dg-options "-O2 -favoid-store-forwarding" } */
+
+typedef union {
+    char arr[2];
+    short value;
+} DataUnion;
+
+short __attribute__ ((noinline))
+ssll (DataUnion *data, char x, char y)
+{
+  data->arr[0] = x;
+  data->arr[1] = y;
+  return data->value;
+}
+
+int main () {
+  DataUnion data = {};
+  short value = ssll (&data, 0, 1);
+  if (value != 1)
+    __builtin_abort ();
+}
\ No newline at end of file
-- 
2.50.1

Reply via email to