On January 9, 2017 6:02:16 PM GMT+01:00, Jeff Law <l...@redhat.com> wrote: >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.
Note we do not preserve traps with -ftrapv -fnon-call-exceptions either. Or generally we happily reorder global sides effects with externally throwing stmts. >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. Fix the pt-null bugs in PTA so we do not need the conservative fallback. As said I have partial patches for this. Richard. >jeff