[Bug tree-optimization/22591] [4.0/4.1 Regression] std::swap() followed by list::erase() produces incorrect list::begin()

steven at gcc dot gnu dot org gcc-bugzilla@gcc.gnu.org
Tue Jul 26 11:57:00 GMT 2005


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



More information about the Gcc-bugs mailing list