https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113879

--- Comment #2 from Andrew Macleod <amacleod at redhat dot com> ---
Not so much a cycle issue as a backward propagation issue.

 <bb 2> :
  goto <bb 6>; [INV]

  <bb 3> :
  _1 = (long unsigned int) j_10;
<..>
  if (j_10 >= -1)
    goto <bb 4>; [INV]
  else
    goto <bb 5>; [INV]

  <bb 4> :
  __builtin_trap ();

  <bb 5> :
  j_18 = j_10 + 1;

  <bb 6> :
  # j_10 = PHI <i_12(D)(2), j_18(5)>
  _9 = i_12(D) + 3;
  if (_9 >= j_10)
    goto <bb 3>; [INV]
  else
    goto <bb 7>; [INV]

  <bb 7> :
  return;

'i' is only ever referenced twice.  Very first thing on the edge from 2->6 as
the initial value for j_10, and then in the calculation of _9 which is then
used in the branch against j_10.

That initial value of i_12 we have no way of knowing can't be INT_MAX.  Its
only later during the calculation _9 = i_12 + 3 that we can infer that i_12
must be INT_MAX-3. 

We certainly know after the branch that 
6->3  (T) i_12(D) :     [irange] int [-INF, 2147483644]

Going back to examine the initial value use on the edge 2->6 is not something
that we would normally expect to have to do.  Its similar to the
__builtin_unreachable() problem in that we can infer the global range of i_12
based on that addition statement, but detecting that is the case in general
circumstance is not trivial as we have to go look at all earlier uses to make
sure they are post dominated by the statement.   

There is also the additional option that I do no believe we currently register
an inferred range on the statement 
  _9 = i_12(D) + 3;
for i_12.   Adding an inferred range for every arithmetic statement would come
with a cost.. not sure exactly what it would be, but we weren't expecting
inferred ranges from the majority of statements. we don't normally need that
because as you can see, we get the ranges right after the branches anyway.  I
could do a dry run and see what the time differential is. 


We could consider adding those inferred ranges at -O3.  we could also consider
an enhancement that works like the builtin_unreachable() removal pass, but
looks at all inferred ranges in the function as well to see if they are
applicable in a global context and adjusts the global value if appropriate. 
Which they would be in a case like this.

Reply via email to