struct cgraph_edge *edge = cgraph_edge (id->src_node, orig_stmt);
POINT_A
              int flags;

              switch (id->transform_call_graph_edges)
                {
              case CB_CGE_DUPLICATE:
                if (edge)
                  cgraph_clone_edge (edge, id->dst_node, stmt,
                                           REG_BR_PROB_BASE, 1,
                                           edge->frequency, true);
                break;

              case CB_CGE_MOVE_CLONES:
                cgraph_set_call_stmt_including_clones (id->dst_node, orig_stmt, 
stmt);
                break;

              case CB_CGE_MOVE:
                if (edge)
                  cgraph_set_call_stmt (edge, stmt);
POINT_B
                break;

              default:
                gcc_unreachable ();
                }

            edge = cgraph_edge (id->src_node, orig_stmt);
POINT_C
            /* Constant propagation on argument done during inlining
               may create new direct call.  Produce an edge for it.  */
            if ((!edge
                 || (edge->indirect_call
                     && id->transform_call_graph_edges == CB_CGE_MOVE_CLONES))
                && is_gimple_call (stmt)
                && (fn = gimple_call_fndecl (stmt)) != NULL)
POINT_D

This code cannot possibly work.

We begin by looking up the edge at POINT_A.
We then move the edge at POINT_B.
We then look up the edge *again* at POINT_C.
Ought we be surprised when we do not find the edge at POINT_D?

After POINT_D, we "fix" the missing edge by creating a new one, which of course is a duplicate, which then of course leads to verification failure.

I think POINT_B is additionally buggy in that we've just corrupted
the cgraph node for the source function when we wanted to change the destination function. I believe we should have done

  case CB_CGE_MOVE:
    edge = cgraph_edge (id->dst_node, orig_stmt);
    cgraph_set_call_stmt (edge, stmt);
    // Possibly fix up indirect->direct call here.

Although, frankly I think it would be easiest to *only* create edges here. There ought to be no problem doing the cgraph_clone_edge here instead of in cgraph_copy_node_for_versioning. That would still preserve all of the information you wanted that's attached to the edges.

Thoughts?


r~

Reply via email to