Hi!

The following testcase ICEs since r15-1579 (addition of late combiner),
because *clrmem_short can't be split.
The problem is that the define_insn uses
   (use (match_operand 1 "nonmemory_operand" "n,a,a,a"))
   (use (match_operand 2 "immediate_operand" "X,R,X,X"))
   (clobber (match_scratch:P 3 "=X,X,X,&a"))
and define_split assumed that if operands[1] is const_int_operand,
match_scratch will be always scratch, and it will be reg only if
it was the last alternative where operands[1] is a reg.
The pattern doesn't guarantee it though, of course RA will not try to
uselessly assign a reg there if it is not needed, but during RA
on the testcase below we match the last alternative, but then comes
late combiner and propagates const_int 3 into operands[1].  And that
matches fine, match_scratch matches either scratch or reg and the constraint
in that case is X for the first variant, so still just fine.  But we won't
split that because the splitters only expect scratch.

The following patch fixes it by using match_scratch instead of scratch,
so that it accepts either.

Bootstrapped on s390x-linux, ok for trunk if regtesting passes as well?

2025-04-16  Jakub Jelinek  <ja...@redhat.com>

        PR target/119834
        * config/s390/s390.md (define_split after *cpymem_short): Use
        (clobber (match_scratch N)) instead of (clobber (scratch)).  Use
        (match_dup 4) and operands[4] instead of (match_dup 3) and operands[3]
        in the last of those.
        (define_split after *clrmem_short): Use (clobber (match_scratch N))
        instead of (clobber (scratch)).
        (define_split after *cmpmem_short): Likewise.

        * g++.target/s390/pr119834.C: New test.

--- gcc/config/s390/s390.md.jj  2025-04-14 07:26:46.447883840 +0200
+++ gcc/config/s390/s390.md     2025-04-16 13:41:04.215127231 +0200
@@ -3597,7 +3597,7 @@ (define_split
         (match_operand:BLK 1 "memory_operand" ""))
    (use (match_operand 2 "const_int_operand" ""))
    (use (match_operand 3 "immediate_operand" ""))
-   (clobber (scratch))]
+   (clobber (match_scratch 4))]
   "reload_completed"
   [(parallel
     [(set (match_dup 0) (match_dup 1))
@@ -3609,7 +3609,7 @@ (define_split
         (match_operand:BLK 1 "memory_operand" ""))
    (use (match_operand 2 "register_operand" ""))
    (use (match_operand 3 "memory_operand" ""))
-   (clobber (scratch))]
+   (clobber (match_scratch 4))]
   "reload_completed"
   [(parallel
     [(unspec [(match_dup 2) (match_dup 3)
@@ -3623,14 +3623,14 @@ (define_split
         (match_operand:BLK 1 "memory_operand" ""))
    (use (match_operand 2 "register_operand" ""))
    (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN)))
-   (clobber (scratch))]
+   (clobber (match_scratch 3))]
   "TARGET_Z10 && reload_completed"
   [(parallel
     [(unspec [(match_dup 2) (const_int 0)
-              (label_ref (match_dup 3))] UNSPEC_EXECUTE)
+             (label_ref (match_dup 4))] UNSPEC_EXECUTE)
      (set (match_dup 0) (match_dup 1))
      (use (const_int 1))])]
-  "operands[3] = gen_label_rtx ();")
+  "operands[4] = gen_label_rtx ();")
 
 (define_split
   [(set (match_operand:BLK 0 "memory_operand" "")
@@ -3852,7 +3852,7 @@ (define_split
         (const_int 0))
    (use (match_operand 1 "const_int_operand" ""))
    (use (match_operand 2 "immediate_operand" ""))
-   (clobber (scratch))
+   (clobber (match_scratch 3))
    (clobber (reg:CC CC_REGNUM))]
   "reload_completed"
   [(parallel
@@ -3866,7 +3866,7 @@ (define_split
         (const_int 0))
    (use (match_operand 1 "register_operand" ""))
    (use (match_operand 2 "memory_operand" ""))
-   (clobber (scratch))
+   (clobber (match_scratch 3))
    (clobber (reg:CC CC_REGNUM))]
   "reload_completed"
   [(parallel
@@ -3882,7 +3882,7 @@ (define_split
         (const_int 0))
    (use (match_operand 1 "register_operand" ""))
    (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN)))
-   (clobber (scratch))
+   (clobber (match_scratch 2))
    (clobber (reg:CC CC_REGNUM))]
   "TARGET_Z10 && reload_completed"
   [(parallel
@@ -4047,7 +4047,7 @@ (define_split
                      (match_operand:BLK 1 "memory_operand" "")))
    (use (match_operand 2 "const_int_operand" ""))
    (use (match_operand 3 "immediate_operand" ""))
-   (clobber (scratch))]
+   (clobber (match_scratch 4))]
   "reload_completed"
   [(parallel
     [(set (reg:CCU CC_REGNUM) (compare:CCU (match_dup 0) (match_dup 1)))
@@ -4060,7 +4060,7 @@ (define_split
                      (match_operand:BLK 1 "memory_operand" "")))
    (use (match_operand 2 "register_operand" ""))
    (use (match_operand 3 "memory_operand" ""))
-   (clobber (scratch))]
+   (clobber (match_scratch 4))]
   "reload_completed"
   [(parallel
     [(unspec [(match_dup 2) (match_dup 3)
@@ -4075,7 +4075,7 @@ (define_split
                      (match_operand:BLK 1 "memory_operand" "")))
    (use (match_operand 2 "register_operand" ""))
    (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN)))
-   (clobber (scratch))]
+   (clobber (match_scratch 3))]
   "TARGET_Z10 && reload_completed"
   [(parallel
     [(unspec [(match_dup 2) (const_int 0)
--- gcc/testsuite/g++.target/s390/pr119834.C.jj 2024-09-17 09:04:10.523093614 
+0200
+++ gcc/testsuite/g++.target/s390/pr119834.C    2025-04-16 20:36:28.964400492 
+0200
@@ -0,0 +1,76 @@
+// PR target/119834
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -march=z900" }
+
+int *a;
+struct A;
+struct B {
+  A begin ();
+  A end ();
+  operator bool * ();
+  void operator++ ();
+};
+template <typename T>
+auto operator| (int, T x) -> decltype (x (0));
+struct A : B { bool a; };
+struct C { A operator () (int); };
+enum D {} d;
+int e;
+void foo ();
+struct E {
+  template <typename T>
+  T *garply ()
+  {
+    if (d)
+      return 0;
+    if (e)
+      foo ();
+    return reinterpret_cast<T *> (f);
+  }
+  template <typename>
+  void bar (long x, bool)
+  {
+    if (&g - f)
+      __builtin_memset (a, 0, x);
+    f += x;
+  }
+  template <typename T>
+  T *baz (T *x, long y, bool z = true)
+  {
+    if (d)
+      return nullptr;
+    bar<T> ((char *)x + y - f, z);
+    return x;
+  }
+  template <typename T>
+  void qux (T x) { baz (x, x->j); }
+  char *f, g;
+} *h;
+struct F {
+  template <typename T>
+  int corge (T x) { x.freddy (this); return 0; }
+  template <typename T>
+  int boo (T x) { corge (x); return 0; }
+} i;
+template <typename T>
+struct G {
+  template <typename U> friend T operator+ (U, G);
+  template <typename U>
+  void waldo (F *x, G y, U z) { x->boo (z + y); }
+  template <typename... Ts>
+  void plugh (E *y, Ts... z) { T *x = y->garply<T> (); x->thud (y, z...); }
+};
+template <typename T> using H = G<T>;
+struct I {
+  static constexpr unsigned j = 2;
+  void thud (E *x, A y) { x->qux (this); for (auto g : y) ; }
+};
+H<I> k;
+struct J {
+  void freddy (F *) { C a; auto b = 0 | a; k.plugh (h, b); }
+};
+H<J> l;
+struct K {
+  void freddy () { l.waldo (&i, l, this); }
+};
+void grault () { K m; m.freddy (); }

        Jakub

Reply via email to