On 12/21/06, Diego Novillo <[EMAIL PROTECTED]> wrote:
Daniel Berlin wrote on 12/21/06 12:21:

> for (i = 0; i < num_ssa_names; i++)
> {
>   tree name = ssa_name (i);
>   if (name && !SSA_NAME_IN_FREELIST (name)
>    DFS (name)
 >
I see that you are not checking for IS_EMPTY_STMT.  Does DFS need to
access things like bb_for_stmt?

I avoided including that part, but yes, we check for it.


In any case, that is not important.  I agree that every SSA name in the
SSA table needs to have a DEF_STMT that is either (a) an empty
statement, or, (b) a valid statement still present in the IL.

Then we've got a bug here :)


Note that this is orthogonal to the problem of whether we free up unused
names from this list.  Every time a statement S disappears, we should
make sure that the names defined by S get their SSA_NAME_DEF_STMT set to
  NOP.

Frankly, I'm a bit surprised that we are running into this. I'd like to
see a test case, if you have one.
Robert, can you attach the testcase you've been working with?
I'm not surprised, but only because I hit it before.   It's pretty rare.

IIRC, what happens it this:

1. We replace all uses of a phi node with something else
2. We then call remove_phi_node with false as the last parameter (only
3 places in the compiler), which ends up destroying the phi node but
not releasing the LHS name (since this is what the last parameter says
whether to do).


void
remove_phi_node (tree phi, tree prev, bool release_lhs_p)
{
...
 release_phi_node (phi);
 if (release_lhs_p)
   release_ssa_name (PHI_RESULT (phi));
}

3. PHI_RESULT (phi) is now in the ssa name list, but SSA_NAME_DEF_STMT
points to a released phi node.

4. We try to walk this at some point later, and crash.

You can see this happens in tree_merge_blocks:

 /* Remove all single-valued PHI nodes from block B of the form
    V_i = PHI <V_j> by propagating V_j to all the uses of V_i.  */
 bsi = bsi_last (a);
 for (phi = phi_nodes (b); phi; phi = phi_nodes (b))
   {
     tree def = PHI_RESULT (phi), use = PHI_ARG_DEF (phi, 0);
...
else
     replace_uses_by (def, use);

     remove_phi_node (phi, NULL, false);
   }

Whenever we hit the else block we end up with a phi node result that
points to a released phi node.  It won't appear in the IR (sine the
phi node has been removed and all the result uses replaced), but will
appear in the ssa_names list.

There are only two other places that call remove_phi_node with false
as the last parameter.
One is moving a phi node, the other appears to be a bug just like the above.

Reply via email to