public inbox for
 help / color / mirror / Atom feed
From: Aldy Hernandez <>
To: Richard Biener <>
Cc: GCC patches <>,
	Andrew MacLeod <>,
Subject: Re: [PATCH] [PR68097] Try to avoid recursing for floats in tree_*_nonnegative_warnv_p.
Date: Wed, 16 Nov 2022 18:38:09 +0100	[thread overview]
Message-ID: <> (raw)
In-Reply-To: <>

On 11/16/22 17:04, Richard Biener wrote:
> On Tue, Nov 15, 2022 at 11:46 AM Aldy Hernandez <> wrote:
>> On 11/15/22 08:15, Richard Biener wrote:
>>> On Mon, Nov 14, 2022 at 8:05 PM Aldy Hernandez <> wrote:
>>>> On 11/14/22 10:12, Richard Biener wrote:
>>>>> On Sat, Nov 12, 2022 at 7:30 PM Aldy Hernandez <> wrote:
>>>>>> It irks me that a PR named "we should track ranges for floating-point
>>>>>> hasn't been closed in this release.  This is an attempt to do just
>>>>>> that.
>>>>>> As mentioned in the PR, even though we track ranges for floats, it has
>>>>>> been suggested that avoiding recursing through SSA defs in
>>>>>> gimple_assign_nonnegative_warnv_p is also a goal.  We can do this with
>>>>>> various ranger components without the need for a heavy handed approach
>>>>>> (i.e. a full ranger).
>>>>>> I have implemented two versions of known_float_sign_p() that answer
>>>>>> the question whether we definitely know the sign for an operation or a
>>>>>> tree expression.
>>>>>> Both versions use get_global_range_query, which is a wrapper to query
>>>>>> global ranges.  This means, that no caching or propagation is done.
>>>>>> In the case of an SSA, we just return the global range for it (think
>>>>>> SSA_NAME_RANGE_INFO).  In the case of a tree code with operands, we
>>>>>> also use get_global_range_query to resolve the operands, and then call
>>>>>> into range-ops, which is our lowest level component.  There is no
>>>>>> ranger or gori involved.  All we're doing is resolving the operation
>>>>>> with the ranges passed.
>>>>>> This is enough to avoid recursing in the case where we definitely know
>>>>>> the sign of a range.  Otherwise, we still recurse.
>>>>>> Note that instead of get_global_range_query(), we could use
>>>>>> get_range_query() which uses a ranger (if active in a pass), or
>>>>>> get_global_range_query if not.  This would allow passes that have an
>>>>>> active ranger (with enable_ranger) to use a full ranger.  These passes
>>>>>> are currently, VRP, loop unswitching, DOM, loop versioning, etc.  If
>>>>>> no ranger is active, get_range_query defaults to global ranges, so
>>>>>> there's no additional penalty.
>>>>>> Would this be acceptable, at least enough to close (or rename the PR ;-))?
>>>>> I think the checks would belong to the gimple_stmt_nonnegative_warnv_p function
>>>>> only (that's the SSA name entry from the ones)?
>>>> That was my first approach, but I thought I'd cover the unary and binary
>>>> operators as well, since they had other callers.  But I'm happy with
>>>> just the top-level tweak.  It's a lot less code :).
>>> @@ -9234,6 +9235,15 @@ bool
>>>    gimple_stmt_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p,
>>>                                    int depth)
>>>    {
>>> +  tree type = gimple_range_type (stmt);
>>> +  if (type && frange::supports_p (type))
>>> +    {
>>> +      frange r;
>>> +      bool sign;
>>> +      return (get_global_range_query ()->range_of_stmt (r, stmt)
>>> +             && r.signbit_p (sign)
>>> +             && sign == false);
>>> +    }
>>> the above means we never fall through to the switch below if
>>> frange::supports_p (type) - that's eventually good enough, I
>>> don't think we ever call this very function directly but it gets
>>> invoked via recursion through operands only.  But of course
>> Woah, sorry.  That was not intended.  For that matter, the patch as
>> posted caused:
>> FAIL: gcc.dg/builtins-10.c (test for excess errors)
>> FAIL: gcc.dg/builtins-57.c (test for excess errors)
>> FAIL: gcc.dg/torture/builtin-nonneg-1.c   -O1  (test for excess errors)
>> FAIL: gcc.dg/torture/builtin-nonneg-1.c   -O2  (test for excess errors)
>> FAIL: gcc.dg/torture/builtin-nonneg-1.c   -O2 -flto
>> -fno-use-linker-plugin -flto-partition=none  (test for excess errors)
>> FAIL: gcc.dg/torture/builtin-nonneg-1.c   -O3 -g  (test for excess errors)
>> FAIL: gcc.dg/torture/builtin-nonneg-1.c   -Os  (test for excess errors)
>> FAIL: gcc.dg/torture/builtin-power-1.c   -O1  (test for excess errors)
>> FAIL: gcc.dg/torture/builtin-power-1.c   -O2  (test for excess errors)
>> FAIL: gcc.dg/torture/builtin-power-1.c   -O2 -flto
>> -fno-use-linker-plugin -flto-partition=none  (test for excess errors)
>> FAIL: gcc.dg/torture/builtin-power-1.c   -O3 -g  (test for excess errors)
>> FAIL: gcc.dg/torture/builtin-power-1.c   -Os  (test for excess errors)
> Did you investigate why?  Because the old patch removed the recursion
> while the new keeps it in case the global range isn't present which isn't
> as nice.

For gcc.dg/builtins-10.c, there are a few calls to 
gimple_stmt_nonnegative* that are being made before we have global 
ranges (ccp1 and forwprop1), so the query returns VARYING (i.e. no known 
sign).  If you're curious, the call to gimple_stmt_nonnegative* comes 
via courtesy of match.pd:

/* Canonicalization of sequences of math builtins.  These rules represent
    IL simplifications but are not necessarily optimizations.

So ISTM, we still need to fall through if we're being called before 
global ranges are available.

After global ranges are available (evrp), we would avoid further lookups 
if it weren't for an unrelated problem I found.

foperator_abs::fold_range() is trying to set a range of [+0.0, +INF], 
but this little snpipet in the frange normalization code adds a -0.0 to 
the range:

   else if (!HONOR_SIGNED_ZEROS (m_type))
       if (real_iszero (&m_max, 1))
	m_max.sign = 0;
       if (real_iszero (&m_min, 0))
	m_min.sign = 1;

We end up with:

[frange] double [-0.0 (-0x0.0p+0), 

I must say this is beyond my paygrade :).  Jakub, it was your suggestion 
to add the snippet above.  Is this correct?  Note that this test is for 

If I comment out the code above, the regressions are fixed, both with my 
current patch or with the original one.  But as I suggested, maybe we 
want the second patch, because we may be called before global ranges are 

IMHO, we could go with the second patch, and fix the ABS problem 

Yay?  Nay?


>> Note that ranger folding calls this function, though it won't run the
>> risk of endless recursion because range_of_stmt uses the LHS, and only
>> use global ranges to solve the LHS.
>> Also, frange::supports_p() does not support all floats:
>>     static bool supports_p (const_tree type)
>>     {
>>       // ?? Decimal floats can have multiple representations for the
>>       // same number.  Supporting them may be as simple as just
>>       // disabling them in singleton_p.  No clue.
>>       return SCALAR_FLOAT_TYPE_P (type) && !DECIMAL_FLOAT_TYPE_P (type);
>>     }
> OK, _Complex types are obviously missing, so are vector ones.
>> Finally, my patch is more conservative than what the *nonnegative_warn*
>> friends do.  We only return true when we're sure about the sign bit and
>> it's FALSE.  As I mentioned elsewhere, tree_call_nonnegative_warn_p()
>> always returns true for:
>>       CASE_CFN_ACOS:
>>       CASE_CFN_ACOS_FN:
>>       CASE_CFN_ACOSH:
>>       CASE_CFN_CABS:
>>       CASE_CFN_CABS_FN:
>> ...
>> ...
>>         /* Always true.  */
>>         return true;
>> This means that we'll return true for a NAN, but we're incorrectly
>> assuming the NAN will be +NAN.  In my proposed patch, we don't make such
>> assumptions.  We only return true if the range is non-negative,
>> including the NAN.
> Yep, the usual issue whether nonnegative means copysign (1, x) produces
> 1 or whether !(x < 0) is true.
>>> I wonder what types are not supported by frange and whether
>>> the manual processing we fall through to does anything meaningful
>>> for those?
>>> I won't ask you to thoroughly answer this now but please put in
>>> a comment reflecting the above before the switch stmt.
>>>      switch (gimple_code (stmt))
>>> Otherwise OK, in case you tree gets back to bootstrapping ;)
>> Updated patch that passes test.
>> OK?  And if so, can I close the PR?
> Yes, I think we now track float ranges - improvements are of course
> always possible.
> Richard.
>> Thanks.
>> Aldy

  reply	other threads:[~2022-11-16 17:38 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-12 18:30 Aldy Hernandez
2022-11-14  9:12 ` Richard Biener
2022-11-14 19:05   ` Aldy Hernandez
2022-11-15  7:15     ` Richard Biener
2022-11-15 10:46       ` Aldy Hernandez
2022-11-16 16:04         ` Richard Biener
2022-11-16 17:38           ` Aldy Hernandez [this message]
2022-11-17  8:01             ` Richard Biener
2022-11-15 13:52   ` Aldy Hernandez
2022-11-16 15:59     ` Richard Biener

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \ \ \ \ \ \ \

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).