https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106590

--- Comment #6 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Cleaned up testcase:

/* { dg-additional-options "-mtune=skylake" { target { i?86-*-* x86_64-*-* } }
} */

typedef struct A { short a; } A;
typedef A *B;
typedef struct C { int c, d; } C;
typedef C *D;

B
foo (void)
{
  static A r = { .a = 1 };
  return &r;
}

D
bar (void)
{
  static C r = { .c = 1, .d = 23 };
  return &r;
}

static inline int __attribute__((always_inline))
baz (short a)
{
  int e = 1, f;
  short g;
  D h;

  switch (a)
    {
    case 1:
      f = 23;
      g = 1;
      break;
    case 2:
      f = 20;
      g = 2;
      break;
    }

  h = bar ();

  if (h->d != f || h->c != g)
    __builtin_abort ();
  return e;
}

int
qux (void)
{
  B i = foo ();
  int e = 1;

  switch (i->a)
    {
    case 1:
    case 2:
      e = baz (i->a);
      break;
    case 3:
      e = 0;
      break;
    }

  return e;
}

int
main ()
{
  qux ();
  return 0;
}

I think this is a latent bug in noce_convert_multiple_sets_1.
For cond
(eq (reg/v:HI 82 [ g ])
    (const_int 1 [0x1]))
and cc_cmp
(eq (reg:CCZ 17 flags)
    (const_int 0 [0]))
when we try_emit_cmove_seq for
(insn 3 35 4 7 (set (reg/v:HI 82 [ g ])
        (const_int 2 [0x2])) "pr106590.c":37:9 84 {*movhi_internal}
     (nil))
insn, we get seq1
(insn 65 0 66 (set (reg:CCZ 17 flags)
        (compare:CCZ (reg/v:HI 82 [ g ])
            (const_int 1 [0x1]))) -1
     (nil))

(insn 66 65 67 (set (reg:QI 96)
        (ne:QI (reg:CCZ 17 flags)
            (const_int 0 [0]))) -1
     (nil))

(insn 67 66 68 (set (reg:HI 95)
        (zero_extend:HI (reg:QI 96))) -1
     (nil))

(insn 68 67 0 (parallel [
            (set (reg:HI 95)
                (plus:HI (reg:HI 95)
                    (const_int 1 [0x1])))
            (clobber (reg:CC 17 flags))
        ]) -1
     (nil))
and seq2
(insn 69 0 70 (set (reg:HI 97)
        (const_int 2 [0x2])) -1
     (nil))

(insn 70 69 0 (set (reg:HI 95)
        (if_then_else:HI (eq (reg:CCZ 17 flags)
                (const_int 0 [0]))
            (reg/v:HI 82 [ g ])
            (reg:HI 97))) -1
     (nil))
and later for
(insn 4 3 36 7 (set (reg/v:SI 84 [ f ])
        (const_int 20 [0x14])) "pr106590.c":36:9 83 {*movsi_internal}
     (nil))
we get seq1
(insn 72 0 71 (set (reg:SI 98)
        (const_int 20 [0x14])) -1
     (nil))

(insn 71 72 73 (set (reg:CCZ 17 flags)
        (compare:CCZ (reg/v:HI 82 [ g ])
            (const_int 1 [0x1]))) -1
     (nil))

(insn 73 71 0 (set (reg/v:SI 84 [ f ])
        (if_then_else:SI (eq (reg:CCZ 17 flags)
                (const_int 0 [0]))
            (reg/v:SI 84 [ f ])
            (reg:SI 98))) -1
     (nil))
and seq2
(insn 74 0 75 (set (reg:SI 99)
        (const_int 20 [0x14])) -1
     (nil))

(insn 75 74 0 (set (reg/v:SI 84 [ f ])
        (if_then_else:SI (eq (reg:CCZ 17 flags)
                (const_int 0 [0]))
            (reg/v:SI 84 [ f ])
            (reg:SI 99))) -1
     (nil))
In the former case, cost1 == cost2, in the latter case cost1 > cost2.
So, we for the first insn choose seq1 and for the second seq2.
That is wrong, because the first seq1 clobbers the (reg 17 flags) register
which is used in cc_cmp/rev_cc_cmp.  So, if we pick that seq1, we may not use
any seq2 afterwards for the latter instructions, need to always select seq1
since then.

Reply via email to