On 01/09/2017 02:36 AM, Richard Biener wrote:


a = 1;
<trigger non-call exception>
a = 2;


If "a" escapes such that its value can be queried in the exception handler,
then the exception handler would be able to observe the first store and thus
it should not be removed.

Yes, and it won't as long as the EH is thrown internally (and thus we have
a CFG reflecting it).  When it's only externally catched we lose of course...

We'd need an Ada testcase to actually show behavior that is not conforming
to an existing language specification though.
I'm not versed enough in Ada to even attempt to pull together a testcase for this.


I suspect we have a similar issue in C++ for sth like

void __attribute__((const)) foo () { throw; }

int x;
void bar ()
{
  x = 1;
  foo ();
  x = 2;
}

where foo is const but not nothrow.
I wouldn't be surprised if there's other problems with const functions that can throw.


We also have to be cognizant of systems where there is memory mapped at
location 0.  When that is true, we must check pt.null and honor it, even if
it pessimizes code.

With -fno-delete-null-pointer-checks (that's what such systems set) PTA computes
0 as "nonlocal" and thus it won't be a singleton points-to solution.
Ah, good.




For

int foo (int *p, int b)
{
  int *q;
  int i = 1;
  if (b)
    q = &i;
  else
    q = (void *)0;
  *q = 2;
  i = 3;
  return *q;
}

So on a system where *0 is a valid memory address, *q = 2 does not make
anything dead, nor does i = 3 unless we were to isolate the THEN/ELSE
blocks.

On a system where *0 traps, there is no way to observe the value of "i" in
the handler.  Thus i = 1 is a dead store.  I believe we must keep the *q = 2
store because it can trigger a signal/exception which is itself an
observable side effect?  Right?

But writing to 0 invokes undefined behavior which we have no obligation to
preserve (unless we make it well-defined with -fnon-call-exceptions -fexceptions
as a GCC extension).
It may invoke undefined behavior, but to date we have explicitly chosen to preserve the *0 = <something> to trigger a fault via the virtual memory system. We kicked this around extensively in Nov 2013 with the introduction of isolation of erroneous paths.

I think part of what pushed us that direction was that a program could catch the signal related to the NULL dereference, then do something sensible in the handler. That also happens to match what the Go language requires.





we remove all stores but the last store to i and the load from q (but we
don't
replace q with &i here, a missed optimization if removing the other stores
is
valid).

But if we remove the *q = 2 store, we remove an observable side effect, the
trap/exception itself if we reach that statement via the ELSE path.

As said above - I don't think we have to care for C/C++ w/o
-fnon-call-exceptions.
So in the immediate term I propose we conditionalize the pt.null check on non-call exceptions. THen I'll look more closely at the example above and see what we can reasonably do there.

jeff

Reply via email to