Hi!

Some target decide to promote certain scalar variables to wider mode,
so their DECL_RTL is a SUBREG with SUBREG_PROMOTED_VAR_P.
When storing to such vars, store_expr takes care of sign or zero extending,
but if we store e.g. through MEM_REF into them, no sign or zero extension
happens and that leads to wrong-code e.g. on the following testcase on
aarch64-linux.

The following patch uses store_expr if we overwrite all the bits and it is
not reversed storage order, i.e. something that store_expr handles normally,
and otherwise (if the most significant bit is (or for pdp11 might be, but
pdp11 doesn't promote) being modified), the code extends manually.

I've bootstrapped/regtested an earlier version of this patch on
{x86_64,i686,aarch64,armv7hl,powerpc64le}-linux; that version head
instead an assert that bitpos is 0 and bitsize GET_MODE_BITSIZE of to_rtx.
That resulted in
g++.dg/warn/Wstrict-aliasing-bogus-char-1.C
gcc.dg/pr87273.c
gcc.dg/torture/pr91656-1.c
gcc.dg/tree-ssa/pr92085-2.c
gcc.dg/tree-ssa/pr94703.c
regressions on powerpc64le and
gcc.c-torture/execute/pr93213.c
on powerpc64le and aarch64, but all of those succeed now with this version.

Ok for trunk?

2020-12-10  Jakub Jelinek  <ja...@redhat.com>

        PR middle-end/98190
        * expr.c (expand_assignment): If to_rtx is a promoted SUBREG,
        ensure sign or zero extension when the most significant bit has
        been overwritten, either through use of store_expr or by extending
        manually.

        * gcc.dg/pr98190.c: New test.

--- gcc/expr.c.jj       2020-12-09 23:50:41.385776978 +0100
+++ gcc/expr.c  2020-12-10 09:35:56.231058928 +0100
@@ -5451,6 +5451,43 @@ expand_assignment (tree to, tree from, b
                                               mode1, to_rtx, to, from,
                                               reversep))
            result = NULL;
+         else if (SUBREG_P (to_rtx)
+                  && SUBREG_PROMOTED_VAR_P (to_rtx))
+           {
+             /* If to_rtx is a promoted subreg, we need to zero or sign
+                extend the value afterwards.  */
+             if (TREE_CODE (to) == MEM_REF
+                 && !REF_REVERSE_STORAGE_ORDER (to)
+                 && known_eq (bitpos, 0)
+                 && known_eq (bitsize, GET_MODE_BITSIZE (GET_MODE (to_rtx))))
+               result = store_expr (from, to_rtx, 0, nontemporal, false);
+             else
+               {
+                 rtx to_rtx1 = to_rtx;
+                 /* Optimize by checking if the overwritten bits
+                    include the most significant bit.  */
+                 if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
+                     || (BYTES_BIG_ENDIAN && known_eq (bitpos, 0))
+                     || (!BYTES_BIG_ENDIAN
+                         && known_eq (bitpos + bitsize,
+                                      GET_MODE_BITSIZE (GET_MODE (to_rtx)))))
+                   to_rtx1 = lowpart_subreg (subreg_unpromoted_mode (to_rtx),
+                                             SUBREG_REG (to_rtx),
+                                             subreg_promoted_mode (to_rtx));
+                 result = store_field (to_rtx1, bitsize, bitpos,
+                                       bitregion_start, bitregion_end,
+                                       mode1, from, get_alias_set (to),
+                                       nontemporal, reversep);
+                 if (to_rtx1 != to_rtx)
+                   {
+                     to_rtx1
+                       = convert_to_mode (subreg_promoted_mode (to_rtx),
+                                          to_rtx1,
+                                          SUBREG_PROMOTED_SIGN (to_rtx));
+                     emit_move_insn (SUBREG_REG (to_rtx), to_rtx1);
+                   }
+               }
+           }
          else
            result = store_field (to_rtx, bitsize, bitpos,
                                  bitregion_start, bitregion_end,
--- gcc/testsuite/gcc.dg/pr98190.c.jj   2020-12-10 09:08:54.838216477 +0100
+++ gcc/testsuite/gcc.dg/pr98190.c      2020-12-10 09:08:54.838216477 +0100
@@ -0,0 +1,33 @@
+/* PR middle-end/98190 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+static int __attribute__((noipa))
+foo (const char *p, const char *q, const int len)
+{
+  for (int i = 0; i < len; p++, q++, i++)
+    {
+      int equal;
+      _Bool x, y;
+      __builtin_memcpy ((char *) &x, p, sizeof x);
+      __builtin_memcpy ((char *) &y, q, sizeof y);
+      equal = (x == y);
+      if (equal <= 0)
+       return equal;
+    }
+  return 1;
+}
+
+int
+main ()
+{
+  const _Bool buf[4] = { 1, 0, 0, 0 };
+#ifdef __aarch64__
+  register long x4 asm ("x4") = 0xdeadbeefULL;
+  register long x5 asm ("x5") = 0xcafebabeULL;
+  asm volatile (""::"r" (x4), "r" (x5));
+#endif
+  if (foo ((char *) &buf[0], (char *) &buf[0], 1) != 1)
+    __builtin_abort ();
+  return 0;
+}

        Jakub

Reply via email to