On 11/08/2011 09:24 PM, Jeff Law wrote:
We don't have access to those assertions as they're removed well prior
to this pass running.  However, if we did, or if we had redundant PHIs
in the stream which were propagated we'd be presented with something like

BB0  if (p_1) goto BB1 else goto BB2

BB1: ... goto BB3
BB2:
BB3: p_2 = phi (p_1 (BB1), 0(BB2))
      *p_2 = 2;


We'd recognize that the edge bb2->bb3 is unexecutable as doing so
leads to a NULL pointer dereference.  Since the edge bb2->bb3 is not a
critical edge, we know that bb2 as a whole is unexecutable.  bb2 is
control dependent on the edge bb0->bb2.

(Side note regarding critical edges: have you tried splitting them before your pass?)

We would remove the edge bb0->bb2 and the control statement if (p_1)
....  That makes BB2 unreachable resulting in

BB0 goto BB1
BB1 ...
BB3 p_2 = phi (p_1)
     *p_2 = 2;

Which would then be optimized into

BB0: ...
      *p_1 = 2;

Which is exactly what I would expect the code to do with the knowledge
that passing 0 to f results in undefined behaviour.

Ok, so that's exactly what I was thinking about. In this case the optimization is obviously allowed by the C standard; you have

    if (p)
      something;
    *p = 0;

and the "*p = 0" has been in some sense translated to

    if (!p)
      something;
    *p = 0;

which is only different on undefined paths. But I'm not sure that more complicated cases, where there are other instructions between the "if" and "*p = 0", would also be allowed by the C standard. For example, I think a function call in the "else" branch, or between the PHI and the dereference should prevent the optimization, because the function call might never return for what we know. Probably a volatile asm too. Does your patch do that? (Testcases! :)).

In general, this is quite different from all other existing GCC optimizations based on undefined behavior. Whenever you trigger undefined behavior, right now the effects do not extend *before* the undefined operation. The proposed pass would change that, so that its effects are a bit more surprising when debugging. If your bug is that you forgot a "return;" in the else branch, you surely wouldn't expect the compiler to swallow the entire branch. Unfortunately debugging at -O0 is not always an option.

Paolo

Reply via email to