Hi,

Lower-subreg decomposes concatn subregs.  Since the regmode-natural-size
changes we could trigger an ICE by insisting the inner mode of such a 
subreg is splittable into words.  But the CONCATN handling in
lower-subreg is specifically for the CONCATNs that lower-subreg.cc 
itself creates, rather than a general operation.  For example, other 
parts of the file assume that a CONCATN has exactly two operands.  There 
are also other asserts that could trigger for preexisting CONCATNs.

This patch sets a flag on these temporary CONCATNs to distinguish them from
preexisting CONCATNs.  'volatil' is free and is used in a similar 
fashion by var-tracking.cc (for CONCAT rather than CONCATN).

Bootstrapped and regtested on x86, power10, and aarch64.
Regtested on risc64.

Regards
 Robin

Co-Authored-By: Richard Sandiford <[email protected]>

        PR rtl-optimization/127443

gcc/ChangeLog:

        * lower-subreg.cc (DECOMPOSED_REGISTER_P): New macro.
        (decompose_register): Mark decomposed.
        (resolve_reg_p): Only resolve decomposed regs.
        (resolve_subreg_p): Move.
        (simplify_subreg_concatn): Remove assert.
        (simplify_gen_subreg_concatn): Use resolve_subreg_p.
        (resolve_operand_for_swap_move_operator): Adjust assert.
        (resolve_debug): Unmark as decomposed.
        * rtl.h (struct GTY): Document usage of volatil in lower-subreg.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/rvv/autovec/pr127443.c: New test.
---
 gcc/lower-subreg.cc                           | 63 ++++++++++---------
 gcc/rtl.h                                     |  1 +
 .../gcc.target/riscv/rvv/autovec/pr127443.c   | 14 +++++
 3 files changed, 50 insertions(+), 28 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127443.c

diff --git a/gcc/lower-subreg.cc b/gcc/lower-subreg.cc
index 548f1b0d4b8..e4d613c5d22 100644
--- a/gcc/lower-subreg.cc
+++ b/gcc/lower-subreg.cc
@@ -76,6 +76,10 @@ along with GCC; see the file COPYING3.  If not see
 #define LOG_COSTS 0
 #define FORCE_LOWERING 0
 
+/* True if a CONCATN was created by decompose_register.  */
+#define DECOMPOSED_REGISTER_P(x) \
+  (RTL_FLAG_CHECK1 ("DECOMPOSED_REGISTER_P", (x), CONCATN)->volatil)
+
 /* Bit N in this bitmap is set if regno N is used in a context in
    which we can decompose it.  */
 static bitmap decomposable_context;
@@ -650,6 +654,7 @@ decompose_register (unsigned int regno)
     RTVEC_ELT (v, i) = gen_reg_rtx_offset (reg, word_mode, i * UNITS_PER_WORD);
 
   PUT_CODE (reg, CONCATN);
+  DECOMPOSED_REGISTER_P (reg) = true;
   XVEC (reg, 0) = v;
 
   if (dump_file)
@@ -661,6 +666,26 @@ decompose_register (unsigned int regno)
     }
 }
 
+/* Return whether we should resolve X into the registers into which it
+   was decomposed.  */
+
+static bool
+resolve_reg_p (rtx x)
+{
+  return GET_CODE (x) == CONCATN && DECOMPOSED_REGISTER_P (x);
+}
+
+/* Return whether X is a SUBREG of a register which we need to
+   resolve.  */
+
+static bool
+resolve_subreg_p (rtx x)
+{
+  if (GET_CODE (x) != SUBREG)
+    return false;
+  return resolve_reg_p (SUBREG_REG (x));
+}
+
 /* Get a SUBREG of a CONCATN.  */
 
 static rtx
@@ -672,6 +697,8 @@ simplify_subreg_concatn (machine_mode outermode, rtx op, 
poly_uint64 orig_byte)
   unsigned int final_offset;
   unsigned int byte;
 
+  gcc_assert (resolve_reg_p (op));
+
   innermode = GET_MODE (op);
 
   if (!interesting_mode_p (innermode, &inner_size, &inner_words))
@@ -682,7 +709,6 @@ simplify_subreg_concatn (machine_mode outermode, rtx op, 
poly_uint64 orig_byte)
 
   /* Must be constant if outer_size is.  */
   byte = orig_byte.to_constant ();
-  gcc_assert (GET_CODE (op) == CONCATN);
   gcc_assert (byte % outer_size == 0);
 
   gcc_assert (byte < inner_size);
@@ -721,7 +747,7 @@ simplify_gen_subreg_concatn (machine_mode outermode, rtx op,
      If OP is a SUBREG of a CONCATN, then it must be a simple mode
      change with the same size and offset 0, or it must extract a
      part.  We shouldn't see anything else here.  */
-  if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == CONCATN)
+  if (resolve_subreg_p (op))
     {
       rtx op2;
 
@@ -749,7 +775,7 @@ simplify_gen_subreg_concatn (machine_mode outermode, rtx op,
       gcc_assert (innermode == GET_MODE (op));
     }
 
-  if (GET_CODE (op) == CONCATN)
+  if (resolve_reg_p (op))
     return simplify_subreg_concatn (outermode, op, byte);
 
   ret = simplify_gen_subreg (outermode, op, innermode, byte);
@@ -765,26 +791,6 @@ simplify_gen_subreg_concatn (machine_mode outermode, rtx 
op,
   return ret;
 }
 
-/* Return whether we should resolve X into the registers into which it
-   was decomposed.  */
-
-static bool
-resolve_reg_p (rtx x)
-{
-  return GET_CODE (x) == CONCATN;
-}
-
-/* Return whether X is a SUBREG of a register which we need to
-   resolve.  */
-
-static bool
-resolve_subreg_p (rtx x)
-{
-  if (GET_CODE (x) != SUBREG)
-    return false;
-  return resolve_reg_p (SUBREG_REG (x));
-}
-
 /* Look for SUBREGs in *LOC which need to be decomposed.  */
 
 static bool
@@ -900,7 +906,7 @@ can_decompose_p (rtx x)
 static rtx
 resolve_operand_for_swap_move_operator (rtx opnd)
 {
-  gcc_assert (GET_CODE (opnd) == CONCATN);
+  gcc_assert (resolve_reg_p (opnd));
   rtx concatn = copy_rtx (opnd);
   rtx op0 = XVECEXP (concatn, 0, 0);
   rtx op1 = XVECEXP (concatn, 0, 1);
@@ -1263,11 +1269,12 @@ resolve_debug (rtx_insn *insn)
 
          if (x)
            *loc = x;
-         else
-           x = copy_rtx (*loc);
        }
-      if (resolve_reg_p (x))
-       *loc = copy_rtx (x);
+      else if (resolve_reg_p (x))
+       {
+         *loc = copy_rtx (x);
+         DECOMPOSED_REGISTER_P (*loc) = false;
+       }
     }
 
   df_insn_rescan (insn);
diff --git a/gcc/rtl.h b/gcc/rtl.h
index d61e576c940..c9dd7d76c30 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -361,6 +361,7 @@ struct GTY((desc("0"), tag("0"),
      In a PREFETCH, this flag indicates that it should be considered a
      scheduling barrier.
      1 in a CONCAT is VAL_NEEDS_RESOLUTION in var-tracking.cc.
+     1 in a CONCATN is used internally by lower-subreg.cc.
      Dumped as "/v" in RTL dumps.  */
   unsigned int volatil : 1;
   /* 1 in a REG if the register is used only in exit code a loop.
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127443.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127443.c
new file mode 100644
index 00000000000..e78c9a2d6a1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127443.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O -march=rv64gcv -mabi=lp64d -g" } */
+
+typedef __attribute__((__vector_size__(16))) __int128 V;
+typedef __attribute__((__vector_size__(16))) char W;
+
+char c;
+
+void
+foo(V v)
+{
+  v &= c;
+  c = ((W)v)[1];
+}
-- 
2.55.0

Reply via email to