Hi!

As written in the PR, the testcase in the patch is miscompiled on
x86_64-linux, because during IRA a *btdi operand is changed from
register to CONST_INT 1 (to which that register was initialized).
Unfortunately when both 2nd and 3rd ZERO_EXTEND operands are constant
integers, *testqi_ext_3{,_rex64} patterns match it wrongly too,
but of course when splitting it into andl/q (which isn't desirable on
TARGET_USE_BT targets anyway) using CCCmode is wrong, as the jump then
looks at the carry bit set by bt{l,q}, while after and{l,q} the interesting
bit is the zero flag.

The following patch is one of the many possibilities to fix it,
bootstrapped/regtested on x86_64-linux and i686-linux.

Other options include just doing != CCCmode tests and remove the const1_rtx
checks from the patch, or on the other side also testing TARGET_USE_BT ||
-Os, or for the define_insn moving *bt<mode> pattern earlier (the splitter
would still need guarding), or perhaps representing bt{l,q} insns
differently in RTL.  I believe this bug is latent starting with 4.4,
when *bt<mode> insn has been added.

2011-05-02  Jakub Jelinek  <ja...@redhat.com>

        PR target/48774
        * config/i386/i386.md (testqi_ext_3_rex64, textqi_ext_3,
        split after testqi_ext_3*): Don't match CCCmode set with
        const1_rtx as last ZERO_EXTRACT operand.

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

--- gcc/config/i386/i386.md.jj  2011-05-02 18:39:23.000000000 +0200
+++ gcc/config/i386/i386.md     2011-05-02 19:09:23.000000000 +0200
@@ -7756,6 +7756,8 @@ (define_insn "*testqi_ext_3_rex64"
                 (const_int 0)))]
   "TARGET_64BIT
    && ix86_match_ccmode (insn, CCNOmode)
+   && (GET_MODE (SET_DEST (PATTERN (insn))) != CCCmode
+       || operands[2] != const1_rtx)
    && INTVAL (operands[1]) > 0
    && INTVAL (operands[2]) >= 0
    /* Ensure that resulting mask is zero or sign extended operand.  */
@@ -7777,6 +7779,8 @@ (define_insn "*testqi_ext_3"
                   (match_operand:SI 2 "const_int_operand" ""))
                 (const_int 0)))]
   "ix86_match_ccmode (insn, CCNOmode)
+   && (GET_MODE (SET_DEST (PATTERN (insn))) != CCCmode
+       || operands[2] != const1_rtx)
    && INTVAL (operands[1]) > 0
    && INTVAL (operands[2]) >= 0
    && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32
@@ -7794,7 +7798,8 @@ (define_split
             (match_operand 3 "const_int_operand" "")
             (match_operand 4 "const_int_operand" ""))
           (const_int 0)]))]
-  "ix86_match_ccmode (insn, CCNOmode)"
+  "ix86_match_ccmode (insn, CCNOmode)
+   && (GET_MODE (operands[0]) != CCCmode || operands[4] != const1_rtx)"
   [(set (match_dup 0) (match_op_dup 1 [(match_dup 2) (const_int 0)]))]
 {
   rtx val = operands[2];
--- gcc/testsuite/gcc.dg/pr48774.c.jj   2011-05-02 19:12:32.000000000 +0200
+++ gcc/testsuite/gcc.dg/pr48774.c      2011-05-02 11:03:55.000000000 +0200
@@ -0,0 +1,38 @@
+/* PR target/48774 */
+/* { dg-do run } */
+/* { dg-options "-O2 -funroll-loops" } */
+
+extern void abort (void);
+unsigned long int s[24]
+  = { 12, ~1, 12, ~2, 12, ~4, 12, ~8, 12, ~16, 12, ~32,
+      12, ~64, 12, ~128, 12, ~256, 12, ~512, 12, ~1024, 12, ~2048 };
+struct { int n; unsigned long *e[12]; } g
+  = { 12, { &s[0], &s[2], &s[4], &s[6], &s[8], &s[10], &s[12], &s[14],
+           &s[16], &s[18], &s[20], &s[22] } };
+int c[12];
+
+__attribute__((noinline, noclone)) void
+foo (void)
+{
+  int i, j;
+  for (i = 0; i < g.n; i++)
+    for (j = 0; j < g.n; j++)
+      {
+       if (i == j && j < g.e[0][0] && (g.e[i][1] & (1UL << j)))
+         abort ();
+       if (j < g.e[0][0] && (g.e[i][1] & (1UL << j)))
+         c[i]++;
+      }
+}
+
+int
+main ()
+{
+  int i;
+  asm volatile ("" : "+m" (s), "+m" (g), "+m" (c));
+  foo ();
+  for (i = 0; i < 12; i++)
+    if (c[i] != 11)
+      abort ();
+  return 0;
+}

        Jakub

Reply via email to