On 5/31/19 9:40 AM, Andrew MacLeod wrote:
> On 5/29/19 7:15 AM, Richard Biener wrote:
>> On Tue, May 28, 2019 at 4:17 PM Andrew MacLeod <amacl...@redhat.com>
>> wrote:
>>> On 5/27/19 9:02 AM, Richard Biener wrote:
>>>> On Fri, May 24, 2019 at 5:50 PM Andrew MacLeod <amacl...@redhat.com>
>>>> wrote:
>>>>>> The above suggests that iff this is done at all it is not in GORI
>>>>>> because
>>>>>> those are not conditional stmts or ranges from feeding those.  The
>>>>>> machinery doing the use-def walking from stmt context also cannot
>>>>>> come along these so I have the suspicion that Ranger cannot handle
>>>>>> telling us that for the stmt following above, for example
>>>>>>
>>>>>>     if (_5 != 0)
>>>>>>
>>>>>> that _5 is not zero?
>>>>>>
>>>>>> Can you clarify?
>>>>> So there are 2 aspects to this.    the range-ops code for DIV_EXPR, if
>>>>> asked for the range of op2 () would return ~[0,0] for _5.
>>>>> But you are also correct in that the walk backwards would not find
>>>>> this.
>>>>>
>>>>> This is similar functionality to how null_derefs are currently
>>>>> handled,
>>>>> and in fact could probably be done simultaneously using the same code
>>>>> base.   I didn't bring null derefs up, but this is a good time :-)
>>>>>
>>>>> There is a separate class used by the gori-cache which tracks the
>>>>> non-nullness property at the block level.    It has a single API:
>>>>> non_null_deref_p (name, bb)    which determines whether the is a
>>>>> dereference in any BB for NAME, which indicates whether the range
>>>>> has an
>>>>> implicit ~[0,0] range in that basic block or not.
>>>> So when we then have
>>>>
>>>>    _1 = *_2; // after this _2 is non-NULL
>>>>    _3 = _1 + 1; // _3 is non-NULL
>>>>    _4 = *_3;
>>>> ...
>>>>
>>>> when a on-demand user asks whether _3 is non-NULL at the
>>>> point of _4 = *_3 we don't have this information?  Since the
>>>> per-BB caching will only say _1 is non-NULL after the BB.
>>>> I'm also not sure whether _3 ever gets non-NULL during
>>>> non-NULL processing of the block since walking immediate uses
>>>> doesn't really help here?
>>> presumably _3 is globally non-null due to the definition being (pointer
>>> + x)  ... ie, _3 has a global range o f ~[0,0] ?
>> No, _3 is ~[0, 0] because it is derived from _1 which is ~[0, 0] and
>> you cannot arrive at NULL by pointer arithmetic from a non-NULL pointer.
> 
> I'm confused.
> 
> _1 was loaded from _2 (thus asserting _2 is non-NULL).  but we have no
> idea what the range of _1 is, so  how do you assert _1 is [~0,0] ?
> The only way I see to determine _3 is non-NULL  is through the _4 = *_3
> statement.
Likewise.  I don't see how we get ~[0,0] for _1, except at the point
after the dereference of _3.


>>>> So this seems to be a fundamental limitation [to the caching scheme],
>>>> not sure if it is bad in practice.
>>>>
>>>> Or am I missing something?
>>>>
>>> Not missing anything  The non-nullness property is maintains globally at
>>> the basic block level.  both _1 and _3 are flagged as being non-null in
>>> the block.  Upon exit, its a bit check.   If the global information does
>>> not have the non-nullness property, then when a request is made for
>>> non-nullness  and the def and the use are both within the same block,
>>> and its flagged as being non-null in that block, then the request is
>>> forced back to a quick walk between the def and the use to see if there
>>> is any non-nulless introduced in between.   Yes, that makes it a linear
>>> walk, but its infrequent, and often short.  to the best of our knowledge
>>> at this point anyway :-)
>> So with the clarification above do we ever see that _3 is non-NULL?
>> I suppose the worker processing _3 = _1 + 1 would ask for
>> _1 non-nullness but we do not record any non-NULL-ness of _1 in
>> this basic-block (but only at its end).  Consider stmts
>>
>>   _4 = (uintptr_t) _2;
>>   _5 = _6 / _4;
>>   _1 = *_2;
>> ...
>>
>> here at _1 we know _2 is not NULL.  But if we ask for non-NULLness
>> of _2 at the definition of _4 we may not compute ~[0, 0] and thus
>> conclude that _6 / _4 does not trap.
> EVRP must look backwards to figure this out since the forward walk will
> process _5 = _6 / _4 before it sees the dereference to _2... so how does
> it know that _4 is non-zero without looking backwards at things after it
> sees the dereference??  Does it actually do this?
During the forward walk we process the assignment to _5, which is _6 /
_4.  We can infer that _4 is nonzero because division by zero is
undefined behavior.  But I'm not sure how EVRP would go back and then
make a determination about _4 unless it's doing so via an equivalence.



> 
>>
>> stmt-level tracking of ranges are sometimes important.  This is
>> something the machinery cannot provide - correct?  At least not
>> optimistically enough with ranges derived about uses.
> 
> Maybe I'm the one missing something, but in the absence of statement
> level exception throwing via 'can_throw_non_call_exceptions' being true,
> any assertion made anywhere in the block to an ssa_name applies to the
> entire block does it not?   ie it doesn't matter if the deference
> happens first thing in the block or last thing, its not going to change
> its value within the block.. its going to be non-null throughout the
> entire block.
No, I don't think it can hold for the entire block.

Consider

  x = p ? 10 : 20;
  foo (x)
  *p = whatever

We don't know p is non-null because foo might not return.  If by way of
the dereference we were to assert p is non-null for the entire block,
then we'd pass the wrong value to foo().

Jeff

Reply via email to