This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug tree-optimization/22591] [4.0/4.1 Regression] std::swap() followed by list::erase() produces incorrect list::begin()
- From: "steven at gcc dot gnu dot org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 26 Jul 2005 11:43:40 -0000
- Subject: [Bug tree-optimization/22591] [4.0/4.1 Regression] std::swap() followed by list::erase() produces incorrect list::begin()
- References: <20050721155650.22591.Simon.Finn@reify.co.uk>
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
------- Additional Comments From steven at gcc dot gnu dot org 2005-07-26 11:43 -------
Smaller test case:
======================================================
void abort ();
typedef struct _Node
{
struct _Node *next, *prev;
} Node;
inline void
swap (Node ** a, Node ** b)
{
Node *tmp = *a;
*a = *b;
*b = tmp;
}
/* Miscompilation seems to happen here. If one removes the if condition
(which should be true) the program works fine. */
void
ListSwap (Node * x, Node * y)
{
Node *tmp;
if (x->next)
{
swap (&x->next, &y->next);
x->next->prev = x->prev->next = x;
}
}
======================================================
Gives this .vars dump:
======================================================
ListSwap (x, y)
{
struct Node * * a;
struct Node * * b;
struct Node * tmp;
struct _Node * D.1610;
<bb 0>:
D.1610 = x->next;
if (D.1610 != 0B) goto <L0>; else goto <L1>;
<L0>:;
a = &x->next;
b = &y->next;
tmp = *a;
*a = *b;
*b = tmp;
x->prev->next = x;
D.1610->prev = x;
<L1>:;
return;
}
======================================================
In the .t22.ccp dump the function still looks OK:
D.1610_10 = x_1->next;
D.1613_11 = x_1->prev;
D.1613_11->next = x_1;
D.1614_12 = D.1613_11->next;
D.1610_10->prev = D.1614_12;
Then .t23.fre causes the problem because the wrong alias info is wrong:
D.1610_10 = D.1610_2;
D.1613_11 = x_1->prev;
D.1613_11->next = x_1;
D.1614_12 = D.1613_11->next;
D.1610_10->prev = D.1614_12;
Note btw how FRE does not replace "D.1614_12" with x_1, which is a missed
optimization.
The alias info is already wrong when it is computed, so at least it is not
some kind of weird updating problem:
ListSwap (xD.1605, yD.1606)
{
struct NodeD.1598 * * aD.1660;
struct NodeD.1598 * * bD.1661;
struct NodeD.1598 * tmpD.1662;
struct NodeD.1598 * D.1663;
struct NodeD.1598 * tmpD.1609;
struct _Node * D.1614;
struct _Node * D.1613;
struct _Node * * D.1612;
struct _Node * * D.1611;
struct _Node * D.1610;
# BLOCK 0
# PRED: ENTRY (fallthru)
# VUSE <TMT.31D.1669_13>;
D.1610_2 = xD.1605_1->nextD.1596;
if (D.1610_2 != 0B) goto <L0>; else goto <L1>;
# SUCC: 1 (true) 2 (false)
# BLOCK 1
# PRED: 0 (true)
<L0>:;
D.1611_4 = &yD.1606_3->nextD.1596;
D.1612_5 = &xD.1605_1->nextD.1596;
aD.1660_6 = (struct NodeD.1598 * *) D.1612_5;
bD.1661_7 = (struct NodeD.1598 * *) D.1611_4;
# VUSE <TMT.32D.1670_14>;
tmpD.1662_8 = *aD.1660_6;
# VUSE <TMT.32D.1670_14>;
D.1663_9 = *bD.1661_7;
# TMT.32D.1670_15 = V_MAY_DEF <TMT.32D.1670_14>;
*aD.1660_6 = D.1663_9;
# TMT.32D.1670_16 = V_MAY_DEF <TMT.32D.1670_15>;
*bD.1661_7 = tmpD.1662_8;
# VUSE <TMT.31D.1669_13>;
D.1610_10 = xD.1605_1->nextD.1596;
# VUSE <TMT.31D.1669_13>;
D.1613_11 = xD.1605_1->prevD.1597;
# TMT.31D.1669_17 = V_MAY_DEF <TMT.31D.1669_13>;
D.1613_11->nextD.1596 = xD.1605_1;
# VUSE <TMT.31D.1669_17>;
D.1614_12 = D.1613_11->nextD.1596;
# TMT.31D.1669_18 = V_MAY_DEF <TMT.31D.1669_17>;
D.1610_10->prevD.1597 = D.1614_12;
# SUCC: 2 (fallthru)
# BLOCK 2
# PRED: 0 (false) 1 (fallthru)
<L1>:;
return;
# SUCC: EXIT
}
Notice that the stores to *a and *b are not killing TMT.31D.1669_13. That
is wrong.
--
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22591