------- Additional Comments From steven at gcc dot gnu dot org 2005-07-26 11:18 ------- My version of t.c: =========================================== void abort (); typedef struct _Node { struct _Node *next, *prev; } Node; void __attribute__ ((noinline)) append (Node * q, Node * p) { p->next = q; p->prev = q; q->next = p; q->prev = p; } 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); swap (&x->prev, &y->prev); x->next->prev = x->prev->next = x; y->next->prev = y->prev->next = y; } } int main () { Node A, A1, B, B1; append (&A, &A1); append (&B, &B1); ListSwap (&A, &B); if (&A != A.next->prev) abort (); } =========================================== compiled with: $ ./xgcc -B. t.c -O2 -m32 -march=pentium4 -da -fdump-tree-vars gives me this for ListSwap: =========================================== ListSwap (x, y) { struct Node * * a; struct Node * * b; struct Node * tmp; struct Node * * a; struct Node * * b; struct Node * tmp; struct _Node * D.1621; struct _Node * D.1614; <bb 0>: D.1614 = x->next; if (D.1614 != 0B) goto <L0>; else goto <L1>; <L0>:; a = &x->next; b = &y->next; tmp = *a; *a = *b; *b = tmp; a = &x->prev; b = &y->prev; tmp = *a; *a = *b; *b = tmp; x->prev->next = x; D.1614->prev = x; D.1621 = y->next; y->prev->next = y; D.1621->prev = y; <L1>:; return; } =========================================== Look at D.1614. It is loaded befoe the conditional, and later there is a store to D.1614->prev. But isn't x->next already something else by then? After all, x->next and y->next are swapped. I checked with Serge Belyshev and he agrees this looks fishy: /QUOTE/ > a = &x->next; > b = &y->next; ... > *a = *b; this changes x->next > D.1614->prev = x; but this still uses old value of x->next /QUOTE/
-- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22591