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