[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