cse: Make sure duplicate elements are not entered into the equivalence set [PR103404]
authorTamar Christina <tamar.christina@arm.com>
Mon, 6 Dec 2021 10:15:15 +0000 (10:15 +0000)
committerTamar Christina <tamar.christina@arm.com>
Mon, 6 Dec 2021 10:16:22 +0000 (10:16 +0000)
CSE uses equivalence classes to keep track of expressions that all have the same
values at the current point in the program.

Normal equivalences through SETs only insert and perform lookups in this set but
equivalence determined from comparisons, e.g.

(insn 46 44 47 7 (set (reg:CCZ 17 flags)
        (compare:CCZ (reg:SI 105 [ iD.2893 ])
            (const_int 0 [0]))) "cse.c":18:22 7 {*cmpsi_ccno_1}
     (expr_list:REG_DEAD (reg:SI 105 [ iD.2893 ])
        (nil)))

creates the equivalence EQ on (reg:SI 105 [ iD.2893 ]) and (const_int 0 [0]).

This causes a merge to happen between the two equivalence sets denoted by
(const_int 0 [0]) and (reg:SI 105 [ iD.2893 ]) respectively.

The operation happens through merge_equiv_classes however this function has an
invariant that the classes to be merge not contain any duplicates.  This is
because it frees entries before merging.

The given testcase when using the supplied flags trigger an ICE due to the
equivalence set being

(rr) p dump_class (class1)
Equivalence chain for (reg:SI 105 [ iD.2893 ]):
(reg:SI 105 [ iD.2893 ])
$3 = void

(rr) p dump_class (class2)
Equivalence chain for (const_int 0 [0]):
(const_int 0 [0])
(reg:SI 97 [ _10 ])
(reg:SI 97 [ _10 ])
$4 = void

This happens because the original INSN being recorded is

(insn 18 17 24 2 (set (subreg:V1SI (reg:SI 97 [ _10 ]) 0)
        (const_vector:V1SI [
                (const_int 0 [0])
            ])) "cse.c":11:9 1363 {*movv1si_internal}
     (expr_list:REG_UNUSED (reg:SI 97 [ _10 ])
        (nil)))

and we end up generating two equivalences. the first one is simply that
reg:SI 97 is 0.  The second one is that 0 can be extracted from the V1SI, so
subreg (subreg:V1SI (reg:SI 97) 0) 0 == 0.  This nested subreg gets folded away
to just reg:SI 97 and we re-insert the same equivalence.

This patch changes it so that if the nunits of a subreg is 1 then don't generate
a vec_select from the subreg as the subreg will be folded away and we get a dup.

gcc/ChangeLog:

PR rtl-optimization/103404
* cse.c (find_sets_in_insn): Don't select elements out of a V1 mode
subreg.

gcc/testsuite/ChangeLog:

PR rtl-optimization/103404
* gcc.target/i386/pr103404.c: New test.

gcc/cse.c
gcc/testsuite/gcc.target/i386/pr103404.c [new file with mode: 0644]

index c1c7d0c..dc5d5ae 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -4275,7 +4275,12 @@ find_sets_in_insn (rtx_insn *insn, vec<struct set> *psets)
       else if (GET_CODE (SET_SRC (x)) == CALL)
        ;
       else if (GET_CODE (SET_SRC (x)) == CONST_VECTOR
-              && GET_MODE_CLASS (GET_MODE (SET_SRC (x))) != MODE_VECTOR_BOOL)
+              && GET_MODE_CLASS (GET_MODE (SET_SRC (x))) != MODE_VECTOR_BOOL
+              /* Prevent duplicates from being generated if the type is a V1
+                 type and a subreg.  Folding this will result in the same
+                 element as folding x itself.  */
+              && !(SUBREG_P (SET_DEST (x))
+                   && known_eq (GET_MODE_NUNITS (GET_MODE (SET_SRC (x))), 1)))
        {
          /* First register the vector itself.  */
          add_to_set (psets, x);
diff --git a/gcc/testsuite/gcc.target/i386/pr103404.c b/gcc/testsuite/gcc.target/i386/pr103404.c
new file mode 100644 (file)
index 0000000..66f3364
--- /dev/null
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-Og -fcse-follow-jumps -fno-dce -fno-early-inlining -fgcse -fharden-conditional-branches -frerun-cse-after-loop -fno-tree-ccp -mavx5124fmaps -std=c99 -w" } */
+
+typedef unsigned __attribute__((__vector_size__ (4))) U;
+typedef unsigned __attribute__((__vector_size__ (16))) V;
+typedef unsigned __attribute__((__vector_size__ (64))) W;
+
+int x, y;
+
+V v;
+W w;
+
+inline
+int bar (U a)
+{
+  a |= x;
+  W k =
+    __builtin_shufflevector (v, 5 / a,
+                            2, 4, 0, 2, 4, 1, 0, 1,
+                            1, 2, 1, 3, 0, 4, 4, 0);
+  w = k;
+  y = 0;
+}
+
+int
+foo ()
+{
+  bar ((U){0xffffffff});
+  for (unsigned i; i < sizeof (foo);)
+    ;
+}
+