Bug 83073 - Range for VR_VARYING | [1, 1]
Summary: Range for VR_VARYING | [1, 1]
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 8.0
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: missed-optimization
Depends on:
Blocks: VRP
  Show dependency treegraph
 
Reported: 2017-11-20 15:18 UTC by Marc Glisse
Modified: 2022-01-13 18:54 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2017-11-20 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Marc Glisse 2017-11-20 15:18:07 UTC
Before r254954, for x | 1 where x is VR_VARYING, we would deduce a VR_ANTI_RANGE ~[0, 0]. Since then, we deduce [-INT_MAX, INT_MAX]. Both make sense, but it is strange that we get something different for VR_VARYING and for a full range, and Richard thinks it is worth looking into (maybe zero_nonzero_bits_from_vr).

-O2 -fdump-tree-optimized-all
int f(int x){return x|1;}
Comment 1 Richard Biener 2017-11-20 15:38:49 UTC
I will have a look.
Comment 2 Richard Biener 2017-11-29 15:15:42 UTC
So for VARYING | 1 we go using the may_be_nonzero stuff in



      else if (code == BIT_IOR_EXPR)
        {
          max = wide_int_to_tree (expr_type,
                                  may_be_nonzero0 | may_be_nonzero1);
          wide_int wmin = must_be_nonzero0 | must_be_nonzero1;
          /* If the input ranges contain only positive values we can
             truncate the minimum of the result range to the maximum
             of the input range minima.  */
          if (int_cst_range0 && int_cst_range1
              && tree_int_cst_sgn (vr0.min) >= 0
              && tree_int_cst_sgn (vr1.min) >= 0)
            {
              wmin = wi::max (wmin, wi::to_wide (vr0.min),
                              TYPE_SIGN (expr_type));
              wmin = wi::max (wmin, wi::to_wide (vr1.min),
                              TYPE_SIGN (expr_type));
            }
          /* If either input range contains only negative values
             we can truncate the minimum of the result range to the
             respective minimum range.  */
          if (int_cst_range0 && tree_int_cst_sgn (vr0.max) < 0)
            wmin = wi::max (wmin, wi::to_wide (vr0.min),
                            TYPE_SIGN (expr_type));
          if (int_cst_range1 && tree_int_cst_sgn (vr1.max) < 0)
            wmin = wi::max (wmin, wi::to_wide (vr1.min),
                            TYPE_SIGN (expr_type));
          min = wide_int_to_tree (expr_type, wmin);

but for [MIN, MAX] we go

          /* For op & or | attempt to optimize:
             [x, y] op z into [x op z, y op z]
             if z is a constant which (for op | its bitwise not) has n
             consecutive least significant bits cleared followed by m 1
             consecutive bits set immediately above it and either
             m + n == precision, or (x >> (m + n)) == (y >> (m + n)).
             The least significant n bits of all the values in the range are
             cleared or set, the m bits above it are preserved and any bits
             above these are required to be the same for all values in the
             range.  */
          if (vr0p && range_int_cst_p (vr0p))
            {
              wide_int w = wi::to_wide (vr1p->min);
              int m = 0, n = 0;
              if (code == BIT_IOR_EXPR)
                w = ~w;
              if (wi::eq_p (w, 0))
 ...

and both cases produce a different outcome (as we see).

I don't see how we can do better.  Well, we can choose to handle
| CST with least significant bit set as ~[0, 0] consistently. Or
we can add a predicate effectively_varying_p () and guard the 2nd case
above with it.

The "proper" result for [MIN,MAX] | 1 is of course a set of every odd number...
Comment 3 Marc Glisse 2017-11-29 15:43:04 UTC
(In reply to Richard Biener from comment #2)
> The "proper" result for [MIN,MAX] | 1 is of course a set of every odd
> number...

Sadly, while we track may-be-nonzero bits in CCP (maybe with the VRP reorg there will be a chance to merge it somehow?), we do not track must-be-nonzero bits.

Note that the original testcase is completely artificial. I needed something known to be nonzero, and at the time x|1 worked so I used that, but it should not be used as if it was an important real-world code that heuristics need to be tuned for.
Comment 4 Andrew Macleod 2020-11-17 17:25:43 UTC
I added a patch to 83072 in which multi-range will now recognize there is no [0,0] in  x|1.

When we add bitmask tracking to ranger, it is in the work queue to track both must-be-zero and must-be-one bits, and integrate that knowledge with range queries.  
(so if (x == 20) would be known false after x = x | 1)

Any additional input on what kind of other information could be attached here to this PR.
Comment 5 Andrew Pinski 2021-07-19 04:08:37 UTC
Take -O2 -fno-tree-fre -fno-tree-ccp -fno-tree-forwprop:
int f(int x)
{
    x = x|1;
    return x & 1;
}

We should be able to figure this out in evrp but don't currently.

VRP can figure it out as it does a match and simplify for the statement.
Comment 6 GCC Commits 2022-01-13 18:52:21 UTC
The master branch has been updated by Andrew Macleod <amacleod@gcc.gnu.org>:

https://gcc.gnu.org/g:49d5fb4feee831868d80fff4d024c271911c92ca

commit r12-6559-g49d5fb4feee831868d80fff4d024c271911c92ca
Author: Andrew MacLeod <amacleod@redhat.com>
Date:   Wed Jan 12 13:31:08 2022 -0500

    Allow more precision when querying from fold_const.
    
    fold_const::expr_not_equal_to queries for a current range, but still uses
    the old value_range class.  This is causing it to miss opportunities when
    ranger can provide something better.
    
            PR tree-optimization/83072
            PR tree-optimization/83073
            PR tree-optimization/97909
            gcc/
            * fold-const.c (expr_not_equal_to): Use a multi-range class.
    
            gcc/testsuite/
            * gcc.dg/pr83072-2.c: New.
            * gcc.dg/pr83073.c: New.
Comment 7 Andrew Macleod 2022-01-13 18:54:25 UTC
Ranger VRP also does match and simplify now for both EVRP and VRP2.