Hi!

The following testcase ICEs on aarch64-linux with -g and
assembles with a warning otherwise, because it emits
ldrb w0,[x0,16]!
instruction which sets the x0 register multiple times.
Due to disabled DCE (from -Og) we end up before REE with:
(insn 12 39 13 2 (set (reg:SI 1 x1 [orig:93 _2 ] [93])
        (zero_extend:SI (mem/c:QI (pre_modify:DI (reg/f:DI 0 x0 [114])
                    (plus:DI (reg/f:DI 0 x0 [114])
                        (const_int 16 [0x10]))) [1 u128_1+0 S1 A128]))) 
"pr103775.c":5:35 117 {*zero_extendqisi2_aarch64}
     (expr_list:REG_INC (reg/f:DI 0 x0 [114])
        (nil)))
(insn 13 12 14 2 (set (reg:DI 0 x0 [orig:112 _2 ] [112])
        (zero_extend:DI (reg:SI 1 x1 [orig:93 _2 ] [93]))) "pr103775.c":5:16 
111 {*zero_extendsidi2_aarch64}
     (nil))
which is valid but not exactly efficient as x0 is dead after the
insn that auto-increments it.  REE turns it into:
(insn 12 39 44 2 (set (reg:DI 0 x0)
        (zero_extend:DI (mem/c:QI (pre_modify:DI (reg/f:DI 0 x0 [114])
                    (plus:DI (reg/f:DI 0 x0 [114])
                        (const_int 16 [0x10]))) [1 u128_1+0 S1 A128]))) 
"pr103775.c":5:35 119 {*zero_extendqidi2_aarch64}
     (expr_list:REG_INC (reg/f:DI 0 x0 [114])
        (nil)))
(insn 44 12 14 2 (set (reg:DI 1 x1)
        (reg:DI 0 x0)) "pr103775.c":5:35 -1
     (nil))
which is invalid because it sets x0 multiple times, one
in SET_DEST of the PATTERN and once in PRE_MODIFY.
As perhaps other passes than REE might suffer from it, IMHO it is better
to reject this during change validation.

Below is one patch that does that only if reload_completed, attached
is another version that does it always even before reload.

I've so far bootstrapped/regtested the first patch on
{x86_64,i686,powerpc64le,armv7hl}-linux, aarch64-linux regtest
is still pending.
If you prefer the second version, I can start testing it momentarily.

2022-03-25  Jakub Jelinek  <ja...@redhat.com>

        PR rtl-optimization/103775
        * recog.cc (check_invalid_inc_dec): New function.
        (insn_invalid_p): Return 1 if REG_INC operand overlaps
        any stored REGs.

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

--- gcc/recog.cc.jj     2022-01-18 11:58:59.802978913 +0100
+++ gcc/recog.cc        2022-03-24 17:46:00.116489292 +0100
@@ -329,6 +329,17 @@ canonicalize_change_group (rtx_insn *ins
     return false;
 }
 
+/* Check if REG_INC argument in *data overlaps a stored REG.  */
+
+static void
+check_invalid_inc_dec (rtx reg, const_rtx, void *data)
+{
+  rtx *pinc = (rtx *) data;
+  if (*pinc == NULL_RTX || MEM_P (reg))
+    return;
+  if (reg_overlap_mentioned_p (reg, *pinc))
+    *pinc = NULL_RTX;
+}
 
 /* This subroutine of apply_change_group verifies whether the changes to INSN
    were valid; i.e. whether INSN can still be recognized.
@@ -384,6 +395,17 @@ insn_invalid_p (rtx_insn *insn, bool in_
 
       if (! constrain_operands (1, get_preferred_alternatives (insn)))
        return 1;
+
+      /* Punt if REG_INC argument overlaps some stored REG.  */
+      for (rtx link = FIND_REG_INC_NOTE (insn, NULL_RTX);
+          link; link = XEXP (link, 1))
+       if (REG_NOTE_KIND (link) == REG_INC)
+         {
+           rtx reg = XEXP (link, 0);
+           note_stores (insn, check_invalid_inc_dec, &reg);
+           if (reg == NULL_RTX)
+             return 1;
+         }
     }
 
   INSN_CODE (insn) = icode;
--- gcc/testsuite/gcc.dg/pr103775.c.jj  2022-03-24 17:51:25.962817859 +0100
+++ gcc/testsuite/gcc.dg/pr103775.c     2022-03-24 17:51:11.024032506 +0100
@@ -0,0 +1,12 @@
+/* PR rtl-optimization/103775 */
+/* { dg-do assemble { target int128 } } */
+/* { dg-options "-Og -fno-forward-propagate -free -g" } */
+
+int
+foo (char a, short b, int c, __int128 d, char e, short f, int g, __int128 h)
+{
+  long i = __builtin_clrsbll ((char) h);
+  __builtin_memset ((char *) &h + 4, d, 3);
+  c &= (char) h;
+  return c + i;
+}

        Jakub
2022-03-25  Jakub Jelinek  <ja...@redhat.com>

        PR rtl-optimization/103775
        * recog.cc (check_invalid_inc_dec): New function.
        (insn_invalid_p): Return 1 if REG_INC operand overlaps
        any stored REGs.

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

--- gcc/recog.cc.jj     2022-01-18 11:58:59.802978913 +0100
+++ gcc/recog.cc        2022-03-24 17:46:00.116489292 +0100
@@ -329,6 +329,17 @@ canonicalize_change_group (rtx_insn *ins
     return false;
 }
 
+/* Check if REG_INC argument in *data overlaps a stored REG.  */
+
+static void
+check_invalid_inc_dec (rtx reg, const_rtx, void *data)
+{
+  rtx *pinc = (rtx *) data;
+  if (*pinc == NULL_RTX || MEM_P (reg))
+    return;
+  if (reg_overlap_mentioned_p (reg, *pinc))
+    *pinc = NULL_RTX;
+}
 
 /* This subroutine of apply_change_group verifies whether the changes to INSN
    were valid; i.e. whether INSN can still be recognized.
@@ -386,6 +397,17 @@ insn_invalid_p (rtx_insn *insn, bool in_
        return 1;
     }
 
+  /* Punt if REG_INC argument overlaps some stored REG.  */
+  for (rtx link = FIND_REG_INC_NOTE (insn, NULL_RTX);
+       link; link = XEXP (link, 1))
+    if (REG_NOTE_KIND (link) == REG_INC)
+      {
+       rtx reg = XEXP (link, 0);
+       note_stores (insn, check_invalid_inc_dec, &reg);
+       if (reg == NULL_RTX)
+         return 1;
+      }
+
   INSN_CODE (insn) = icode;
   return 0;
 }
--- gcc/testsuite/gcc.dg/pr103775.c.jj  2022-03-24 17:51:25.962817859 +0100
+++ gcc/testsuite/gcc.dg/pr103775.c     2022-03-24 17:51:11.024032506 +0100
@@ -0,0 +1,12 @@
+/* PR rtl-optimization/103775 */
+/* { dg-do assemble { target int128 } } */
+/* { dg-options "-Og -fno-forward-propagate -free -g" } */
+
+int
+foo (char a, short b, int c, __int128 d, char e, short f, int g, __int128 h)
+{
+  long i = __builtin_clrsbll ((char) h);
+  __builtin_memset ((char *) &h + 4, d, 3);
+  c &= (char) h;
+  return c + i;
+}

Reply via email to