On 01/20/2017 03:17 AM, Richard Biener wrote:
On Thu, Jan 19, 2017 at 5:53 PM, Martin Sebor <mse...@gmail.com> wrote:
On 01/19/2017 05:45 AM, Richard Biener wrote:

On Thu, Jan 19, 2017 at 1:17 PM, Aldy Hernandez <al...@redhat.com> wrote:

In the attached testcase, we have a clearly bounded case of alloca which
is
being incorrectly reported:

void g (int *p, int *q)
{
   size_t n = (size_t)(p - q);

   if (n < 10)
     f (__builtin_alloca (n));
}

The problem is that VRP gives us an anti-range for `n' which may be out
of
range:

  # RANGE ~[2305843009213693952, 16140901064495857663]
   n_9 = (long unsigned int) _4;

We do a less than stellar job with casts and VR_ANTI_RANGE's, mostly
because
we're trying various heuristics to make up for the fact that we have
crappy
range info from VRP.  More specifically, we're basically punting on an
VR_ANTI_RANGE and ignoring that the casted result (n_9) has a bound later
on.

Luckily, we already have code to check simple ranges coming into the
alloca
by looking into all the basic blocks feeding it.  The attached patch
delays
the final decision on anti ranges until we have examined the basic blocks
and determined for that we are definitely out of range.

I expect all this to disappear with Andrew's upcoming range info
overhaul.

OK for trunk?


I _really_ wonder why all the range consuming warnings are not emitted
from VRP itself (like we do for -Warray-bounds).  There we'd still see
a range for the argument derived from the if () rather than needing to
do our own mini-VRP from the needessly "incomplete" range-info on
SSA vars.


Can you explain why the range info is only available in VRP and
not outside, via the get_range_info() API?  It sounds as though
the API shouldn't be relied on (it was virtually unused before
GCC 7).

It's very simple.  Look at the testcase from above

void g (int *p, int *q)
{
   size_t n = (size_t)(p - q);

   if (n < 10)
     f (__builtin_alloca (n));
}

The IL outside of VRP is

  <bb 2> [100.00%]:
  p.0_1 = (long int) p_7(D);
  q.1_2 = (long int) q_8(D);
  _3 = p.0_1 - q.1_2;
  _4 = _3 /[ex] 4;
  n_9 = (size_t) _4;
  if (n_9 <= 9)
    goto <bb 3>; [36.64%]
  else
    goto <bb 4>; [63.36%]

  <bb 3> [36.64%]:
  _5 = __builtin_alloca (n_9);
  f (_5);

so there is no SSA name we can tack a range to covering the n_9 <= 9
condition that dominates __builtin_alloca.  Inside VRP we have

  <bb 2> [100.00%]:
  p.0_1 = (long int) p_7(D);
  q.1_2 = (long int) q_8(D);
  _3 = p.0_1 - q.1_2;
  _4 = _3 /[ex] 4;
  n_9 = (size_t) _4;
  if (n_9 <= 9)
    goto <bb 3>; [36.64%]
  else
    goto <bb 4>; [63.36%]

  <bb 3> [36.64%]:
  n_13 = ASSERT_EXPR <n_9, n_9 <= 9>;
  _5 = __builtin_alloca (n_13);
  f (_5);

and viola - now the alloca call uses n_13 which is defined at a point
dominated by if (n_9 <= 9) and thus it has an improved range:

n_13: [0, 9]  EQUIVALENCES: { n_9 } (1 elements)

Yes, I remember getting much better range information when doing things within VRP2, however since VRP2 runs after jump threading sometimes I'd get more false positives.

Tell you what, for GCC8 I volunteer to rewrite gimple-ssa-warn-alloca.c within VRP (or using whatever range information we decide upon or is ready for GCC8). In the meantime, can we fix the PR with my patch (or a similar approach)?

Aldy

Reply via email to