------- 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