[Bug rtl-optimization/23560] New: [4.0 Regression] Strength-reduction breaking unsigned COMPARE

jakub at gcc dot gnu dot org gcc-bugzilla@gcc.gnu.org
Thu Aug 25 14:09:00 GMT 2005


struct rtattr
{
  unsigned short rta_len;
  unsigned short rta_type;
};

__attribute__ ((noinline))
int inet_check_attr (void *r, struct rtattr **rta)
{
  int i;

  for (i = 1; i <= 14; i++)
    {
      struct rtattr *attr = rta[i - 1];
      if (attr)
        {
          if (attr->rta_len - sizeof (struct rtattr) < 4)
            return -22;
          if (i != 9 && i != 8)
            rta[i - 1] = attr + 1;
        }
    }
  return 0;
}

extern void abort (void);

int
main (void)
{
  struct rtattr rt[2];
  struct rtattr *rta[14];
  int i;

  rt[0].rta_len = sizeof (struct rtattr) + 8;
  rt[0].rta_type = 0;
  rt[1] = rt[0];
  for (i = 0; i < 14; i++)
    rta[i] = &rt[0];
  if (inet_check_attr (0, rta) != 0)
    abort ();
  for (i = 0; i < 14; i++)
    if (rta[i] != &rt[i != 7 && i != 8])
      abort ();
  for (i = 0; i < 14; i++)
    rta[i] = &rt[0];
  rta[1] = 0;
  rt[1].rta_len -= 8;
  rta[5] = &rt[1];
  if (inet_check_attr (0, rta) != -22)
    abort ();
  for (i = 0; i < 14; i++)
    if (i == 1 && rta[i] != 0)
      abort ();
    else if (i != 1 && i <= 5 && rta[i] != &rt[1])
      abort ();
    else if (i > 5 && rta[i] != &rt[0])
      abort ();
  return 0;
}

is miscompiled on i386-linux at -Os.  The bug seems to be in strength-reduction.
The loop starts with unsigned int ivtmp.14 = -7U; and keeps cycling until
ivtmp.14 >= 7U, ivtmp.14 is incremented by 1 in each iteration and the
if (i != 9 && i != 8) test has been transformed into if (ivtmp.14 <= 1U) test.
But, strength reduction transforms:
(insn 42 40 43 4 (set (reg:CC 17 flags)
        (compare:CC (reg:SI 61 [ ivtmp.14 ])
            (const_int 1 [0x1]))) 5 {*cmpsi_1_insn} (nil)
    (nil))

(jump_insn 43 42 45 4 (set (pc)
        (if_then_else (leu (reg:CC 17 flags)
                (const_int 0 [0x0]))
            (label_ref 49)
            (pc))) 489 {*jcc_1} (nil)
    (expr_list:REG_BR_PROB (const_int 2100 [0x834])
        (nil)))

into:
(insn 42 40 43 4 (set (reg:CC 17 flags)
        (compare:CC (reg/f:SI 75)
            (reg/f:SI 77))) -1 (nil)
    (nil))

(jump_insn 43 42 45 4 (set (pc)
        (if_then_else (leu (reg:CC 17 flags)
                (const_int 0 [0x0]))
            (label_ref 49)
            (pc))) -1 (nil)
    (expr_list:REG_BR_PROB (const_int 2100 [0x834])
        (nil)))

where pseudo 77 is constant, initialized to:
(insn 85 84 86 0 (parallel [
            (set (reg/f:SI 77)
                (plus:SI (reg/v/f:SI 66 [ rta ])
                    (const_int 4 [0x4])))
            (clobber (reg:CC 17 flags))
        ]) -1 (nil)
    (nil))
and pseudo 75 is initialized to:
(insn 82 14 84 0 (parallel [
            (set (reg/f:SI 75)
                (plus:SI (reg/v/f:SI 66 [ rta ])
                    (const_int -28 [0xffffffffffffffe4])))
            (clobber (reg:CC 17 flags))
        ]) -1 (nil)
    (nil))
and increment by 4 at the end of each iteration.
This transformation should work fine for EQ/NE comparisons, but really can't
work for other unsigned comparisons (and not really sure about GT/LT/GE/LE).
The testcase is distilled from Linux kernel, so this is quite important problem.

-- 
           Summary: [4.0 Regression] Strength-reduction breaking unsigned
                    COMPARE
           Product: gcc
           Version: 4.0.2
            Status: UNCONFIRMED
          Severity: critical
          Priority: P2
         Component: rtl-optimization
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: jakub at gcc dot gnu dot org
                CC: gcc-bugs at gcc dot gnu dot org
GCC target triplet: i386-linux


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=23560



More information about the Gcc-bugs mailing list