diff mbox series

[PATCH-3v2] Value Range: Add range op for builtin isnormal

Message ID d93797eb-a0ed-49e4-b919-c613772c0f36@linux.ibm.com
State New
Headers show
Series [PATCH-3v2] Value Range: Add range op for builtin isnormal | expand

Commit Message

HAO CHEN GUI May 30, 2024, 2:46 a.m. UTC
Hi,
  This patch adds the range op for builtin isnormal. It also adds two
help function in frange to detect range of normal floating-point and
range of subnormal or zero.

  Compared to previous version, the main change is to set the range to
1 if it's normal number otherwise to 0.
https://gcc.gnu.org/pipermail/gcc-patches/2024-May/652221.html

  Bootstrapped and tested on x86 and powerpc64-linux BE and LE with no
regressions. Is it OK for the trunk?

Thanks
Gui Haochen

ChangeLog
Value Range: Add range op for builtin isnormal

The former patch adds optab for builtin isnormal. Thus builtin isnormal
might not be folded at front end.  So the range op for isnormal is needed
for value range analysis.  This patch adds range op for builtin isnormal.

gcc/
	* gimple-range-op.cc (class cfn_isfinite): New.
	(op_cfn_finite): New variables.
	(gimple_range_op_handler::maybe_builtin_call): Handle
	CFN_BUILT_IN_ISFINITE.
	* value-range.h (class frange): Declare known_isnormal and
	known_isdenormal_or_zero.
	(frange::known_isnormal): Define.
	(frange::known_isdenormal_or_zero): Define.

gcc/testsuite/
	* gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c: New test.

patch.diff

Comments

HAO CHEN GUI June 20, 2024, 6:58 a.m. UTC | #1
Hi,
  Gently ping it.
https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653095.html

Thanks
Gui Haochen

在 2024/5/30 10:46, HAO CHEN GUI 写道:
> Hi,
>   This patch adds the range op for builtin isnormal. It also adds two
> help function in frange to detect range of normal floating-point and
> range of subnormal or zero.
> 
>   Compared to previous version, the main change is to set the range to
> 1 if it's normal number otherwise to 0.
> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/652221.html
> 
>   Bootstrapped and tested on x86 and powerpc64-linux BE and LE with no
> regressions. Is it OK for the trunk?
> 
> Thanks
> Gui Haochen
> 
> ChangeLog
> Value Range: Add range op for builtin isnormal
> 
> The former patch adds optab for builtin isnormal. Thus builtin isnormal
> might not be folded at front end.  So the range op for isnormal is needed
> for value range analysis.  This patch adds range op for builtin isnormal.
> 
> gcc/
> 	* gimple-range-op.cc (class cfn_isfinite): New.
> 	(op_cfn_finite): New variables.
> 	(gimple_range_op_handler::maybe_builtin_call): Handle
> 	CFN_BUILT_IN_ISFINITE.
> 	* value-range.h (class frange): Declare known_isnormal and
> 	known_isdenormal_or_zero.
> 	(frange::known_isnormal): Define.
> 	(frange::known_isdenormal_or_zero): Define.
> 
> gcc/testsuite/
> 	* gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c: New test.
> 
> patch.diff
> diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
> index 5ec5c828fa4..6787f532f11 100644
> --- a/gcc/gimple-range-op.cc
> +++ b/gcc/gimple-range-op.cc
> @@ -1289,6 +1289,61 @@ public:
>    }
>  } op_cfn_isfinite;
> 
> +//Implement range operator for CFN_BUILT_IN_ISNORMAL
> +class cfn_isnormal :  public range_operator
> +{
> +public:
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
> +  virtual bool fold_range (irange &r, tree type, const frange &op1,
> +			   const irange &, relation_trio) const override
> +  {
> +    if (op1.undefined_p ())
> +      return false;
> +
> +    if (op1.known_isnormal ())
> +      {
> +	wide_int one = wi::one (TYPE_PRECISION (type));
> +	r.set (type, one, one);
> +	return true;
> +      }
> +
> +    if (op1.known_isnan ()
> +	|| op1.known_isinf ()
> +	|| op1.known_isdenormal_or_zero ())
> +      {
> +	r.set_zero (type);
> +	return true;
> +      }
> +
> +    r.set_varying (type);
> +    return true;
> +  }
> +  virtual bool op1_range (frange &r, tree type, const irange &lhs,
> +			  const frange &, relation_trio) const override
> +  {
> +    if (lhs.undefined_p ())
> +      return false;
> +
> +    if (lhs.zero_p ())
> +      {
> +	r.set_varying (type);
> +	return true;
> +      }
> +
> +    if (!range_includes_zero_p (lhs))
> +      {
> +	nan_state nan (false);
> +	r.set (type, real_min_representable (type),
> +	       real_max_representable (type), nan);
> +	return true;
> +      }
> +
> +    r.set_varying (type);
> +    return true;
> +  }
> +} op_cfn_isnormal;
> +
>  // Implement range operator for CFN_BUILT_IN_
>  class cfn_parity : public range_operator
>  {
> @@ -1391,6 +1446,11 @@ gimple_range_op_handler::maybe_builtin_call ()
>        m_operator = &op_cfn_isfinite;
>        break;
> 
> +    case CFN_BUILT_IN_ISNORMAL:
> +      m_op1 = gimple_call_arg (call, 0);
> +      m_operator = &op_cfn_isnormal;
> +      break;
> +
>      CASE_CFN_COPYSIGN_ALL:
>        m_op1 = gimple_call_arg (call, 0);
>        m_op2 = gimple_call_arg (call, 1);
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c b/gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c
> new file mode 100644
> index 00000000000..c4df4d839b0
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c
> @@ -0,0 +1,37 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-evrp" } */
> +
> +#include <math.h>
> +void link_error();
> +
> +void test1 (double x)
> +{
> +  if (x < __DBL_MAX__ && x > __DBL_MIN__ && !__builtin_isnormal (x))
> +    link_error ();
> +
> +  if (x < -__DBL_MIN__ && x > -__DBL_MAX__ && !__builtin_isnormal (x))
> +    link_error ();
> +}
> +
> +void test2 (float x)
> +{
> +  if (x < __FLT_MAX__ && x > __FLT_MIN__ && !__builtin_isnormal (x))
> +    link_error ();
> +
> +  if (x < -__FLT_MIN__ && x > - __FLT_MAX__ && !__builtin_isnormal (x))
> +    link_error ();
> +}
> +
> +void test3 (double x)
> +{
> +  if (__builtin_isnormal (x) && __builtin_isinf (x))
> +    link_error ();
> +}
> +
> +void test4 (float x)
> +{
> +  if (__builtin_isnormal (x) && __builtin_isinf (x))
> +    link_error ();
> +}
> +
> +/* { dg-final { scan-tree-dump-not "link_error" "evrp" } } */
> diff --git a/gcc/value-range.h b/gcc/value-range.h
> index 37ce91dc52d..1443d1906e5 100644
> --- a/gcc/value-range.h
> +++ b/gcc/value-range.h
> @@ -588,6 +588,8 @@ public:
>    bool maybe_isinf () const;
>    bool signbit_p (bool &signbit) const;
>    bool nan_signbit_p (bool &signbit) const;
> +  bool known_isnormal () const;
> +  bool known_isdenormal_or_zero () const;
> 
>  protected:
>    virtual bool contains_p (tree cst) const override;
> @@ -1650,6 +1652,33 @@ frange::known_isfinite () const
>    return (!maybe_isnan () && !real_isinf (&m_min) && !real_isinf (&m_max));
>  }
> 
> +// Return TRUE if range is known to be normal.
> +
> +inline bool
> +frange::known_isnormal () const
> +{
> +  if (!known_isfinite ())
> +    return false;
> +
> +  machine_mode mode = TYPE_MODE (type ());
> +  return (!real_isdenormal (&m_min, mode) && !real_isdenormal (&m_max, mode)
> +	  && !real_iszero (&m_min) && !real_iszero (&m_max)
> +	  && (!real_isneg (&m_min) || real_isneg (&m_max)));
> +}
> +
> +// Return TRUE if range is known to be denormal.
> +
> +inline bool
> +frange::known_isdenormal_or_zero () const
> +{
> +  if (!known_isfinite ())
> +    return false;
> +
> +  machine_mode mode = TYPE_MODE (type ());
> +  return ((real_isdenormal (&m_min, mode) || real_iszero (&m_min))
> +	  && (real_isdenormal (&m_max, mode) || real_iszero (&m_max)));
> +}
> +
>  // Return TRUE if range may be infinite.
> 
>  inline bool
HAO CHEN GUI July 1, 2024, 1:12 a.m. UTC | #2
Hi,
  Gently ping it.
https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653095.html

Thanks
Gui Haochen

在 2024/6/24 9:41, HAO CHEN GUI 写道:
> Hi,
>   Gently ping it.
> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653095.html
> 
> Thanks
> Gui Haochen
> 
> 在 2024/6/20 14:58, HAO CHEN GUI 写道:
>> Hi,
>>   Gently ping it.
>> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653095.html
>>
>> Thanks
>> Gui Haochen
>>
>> 在 2024/5/30 10:46, HAO CHEN GUI 写道:
>>> Hi,
>>>   This patch adds the range op for builtin isnormal. It also adds two
>>> help function in frange to detect range of normal floating-point and
>>> range of subnormal or zero.
>>>
>>>   Compared to previous version, the main change is to set the range to
>>> 1 if it's normal number otherwise to 0.
>>> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/652221.html
>>>
>>>   Bootstrapped and tested on x86 and powerpc64-linux BE and LE with no
>>> regressions. Is it OK for the trunk?
>>>
>>> Thanks
>>> Gui Haochen
>>>
>>> ChangeLog
>>> Value Range: Add range op for builtin isnormal
>>>
>>> The former patch adds optab for builtin isnormal. Thus builtin isnormal
>>> might not be folded at front end.  So the range op for isnormal is needed
>>> for value range analysis.  This patch adds range op for builtin isnormal.
>>>
>>> gcc/
>>> 	* gimple-range-op.cc (class cfn_isfinite): New.
>>> 	(op_cfn_finite): New variables.
>>> 	(gimple_range_op_handler::maybe_builtin_call): Handle
>>> 	CFN_BUILT_IN_ISFINITE.
>>> 	* value-range.h (class frange): Declare known_isnormal and
>>> 	known_isdenormal_or_zero.
>>> 	(frange::known_isnormal): Define.
>>> 	(frange::known_isdenormal_or_zero): Define.
>>>
>>> gcc/testsuite/
>>> 	* gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c: New test.
>>>
>>> patch.diff
>>> diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
>>> index 5ec5c828fa4..6787f532f11 100644
>>> --- a/gcc/gimple-range-op.cc
>>> +++ b/gcc/gimple-range-op.cc
>>> @@ -1289,6 +1289,61 @@ public:
>>>    }
>>>  } op_cfn_isfinite;
>>>
>>> +//Implement range operator for CFN_BUILT_IN_ISNORMAL
>>> +class cfn_isnormal :  public range_operator
>>> +{
>>> +public:
>>> +  using range_operator::fold_range;
>>> +  using range_operator::op1_range;
>>> +  virtual bool fold_range (irange &r, tree type, const frange &op1,
>>> +			   const irange &, relation_trio) const override
>>> +  {
>>> +    if (op1.undefined_p ())
>>> +      return false;
>>> +
>>> +    if (op1.known_isnormal ())
>>> +      {
>>> +	wide_int one = wi::one (TYPE_PRECISION (type));
>>> +	r.set (type, one, one);
>>> +	return true;
>>> +      }
>>> +
>>> +    if (op1.known_isnan ()
>>> +	|| op1.known_isinf ()
>>> +	|| op1.known_isdenormal_or_zero ())
>>> +      {
>>> +	r.set_zero (type);
>>> +	return true;
>>> +      }
>>> +
>>> +    r.set_varying (type);
>>> +    return true;
>>> +  }
>>> +  virtual bool op1_range (frange &r, tree type, const irange &lhs,
>>> +			  const frange &, relation_trio) const override
>>> +  {
>>> +    if (lhs.undefined_p ())
>>> +      return false;
>>> +
>>> +    if (lhs.zero_p ())
>>> +      {
>>> +	r.set_varying (type);
>>> +	return true;
>>> +      }
>>> +
>>> +    if (!range_includes_zero_p (lhs))
>>> +      {
>>> +	nan_state nan (false);
>>> +	r.set (type, real_min_representable (type),
>>> +	       real_max_representable (type), nan);
>>> +	return true;
>>> +      }
>>> +
>>> +    r.set_varying (type);
>>> +    return true;
>>> +  }
>>> +} op_cfn_isnormal;
>>> +
>>>  // Implement range operator for CFN_BUILT_IN_
>>>  class cfn_parity : public range_operator
>>>  {
>>> @@ -1391,6 +1446,11 @@ gimple_range_op_handler::maybe_builtin_call ()
>>>        m_operator = &op_cfn_isfinite;
>>>        break;
>>>
>>> +    case CFN_BUILT_IN_ISNORMAL:
>>> +      m_op1 = gimple_call_arg (call, 0);
>>> +      m_operator = &op_cfn_isnormal;
>>> +      break;
>>> +
>>>      CASE_CFN_COPYSIGN_ALL:
>>>        m_op1 = gimple_call_arg (call, 0);
>>>        m_op2 = gimple_call_arg (call, 1);
>>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c b/gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c
>>> new file mode 100644
>>> index 00000000000..c4df4d839b0
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c
>>> @@ -0,0 +1,37 @@
>>> +/* { dg-do compile } */
>>> +/* { dg-options "-O2 -fdump-tree-evrp" } */
>>> +
>>> +#include <math.h>
>>> +void link_error();
>>> +
>>> +void test1 (double x)
>>> +{
>>> +  if (x < __DBL_MAX__ && x > __DBL_MIN__ && !__builtin_isnormal (x))
>>> +    link_error ();
>>> +
>>> +  if (x < -__DBL_MIN__ && x > -__DBL_MAX__ && !__builtin_isnormal (x))
>>> +    link_error ();
>>> +}
>>> +
>>> +void test2 (float x)
>>> +{
>>> +  if (x < __FLT_MAX__ && x > __FLT_MIN__ && !__builtin_isnormal (x))
>>> +    link_error ();
>>> +
>>> +  if (x < -__FLT_MIN__ && x > - __FLT_MAX__ && !__builtin_isnormal (x))
>>> +    link_error ();
>>> +}
>>> +
>>> +void test3 (double x)
>>> +{
>>> +  if (__builtin_isnormal (x) && __builtin_isinf (x))
>>> +    link_error ();
>>> +}
>>> +
>>> +void test4 (float x)
>>> +{
>>> +  if (__builtin_isnormal (x) && __builtin_isinf (x))
>>> +    link_error ();
>>> +}
>>> +
>>> +/* { dg-final { scan-tree-dump-not "link_error" "evrp" } } */
>>> diff --git a/gcc/value-range.h b/gcc/value-range.h
>>> index 37ce91dc52d..1443d1906e5 100644
>>> --- a/gcc/value-range.h
>>> +++ b/gcc/value-range.h
>>> @@ -588,6 +588,8 @@ public:
>>>    bool maybe_isinf () const;
>>>    bool signbit_p (bool &signbit) const;
>>>    bool nan_signbit_p (bool &signbit) const;
>>> +  bool known_isnormal () const;
>>> +  bool known_isdenormal_or_zero () const;
>>>
>>>  protected:
>>>    virtual bool contains_p (tree cst) const override;
>>> @@ -1650,6 +1652,33 @@ frange::known_isfinite () const
>>>    return (!maybe_isnan () && !real_isinf (&m_min) && !real_isinf (&m_max));
>>>  }
>>>
>>> +// Return TRUE if range is known to be normal.
>>> +
>>> +inline bool
>>> +frange::known_isnormal () const
>>> +{
>>> +  if (!known_isfinite ())
>>> +    return false;
>>> +
>>> +  machine_mode mode = TYPE_MODE (type ());
>>> +  return (!real_isdenormal (&m_min, mode) && !real_isdenormal (&m_max, mode)
>>> +	  && !real_iszero (&m_min) && !real_iszero (&m_max)
>>> +	  && (!real_isneg (&m_min) || real_isneg (&m_max)));
>>> +}
>>> +
>>> +// Return TRUE if range is known to be denormal.
>>> +
>>> +inline bool
>>> +frange::known_isdenormal_or_zero () const
>>> +{
>>> +  if (!known_isfinite ())
>>> +    return false;
>>> +
>>> +  machine_mode mode = TYPE_MODE (type ());
>>> +  return ((real_isdenormal (&m_min, mode) || real_iszero (&m_min))
>>> +	  && (real_isdenormal (&m_max, mode) || real_iszero (&m_max)));
>>> +}
>>> +
>>>  // Return TRUE if range may be infinite.
>>>
>>>  inline bool
HAO CHEN GUI July 22, 2024, 2:09 a.m. UTC | #3
Hi,
  Gently ping it.
https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653095.html

Thanks
Gui Haochen

在 2024/7/1 9:12, HAO CHEN GUI 写道:
> Hi,
>   Gently ping it.
> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653095.html
> 
> Thanks
> Gui Haochen
> 
> 在 2024/6/24 9:41, HAO CHEN GUI 写道:
>> Hi,
>>   Gently ping it.
>> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653095.html
>>
>> Thanks
>> Gui Haochen
>>
>> 在 2024/6/20 14:58, HAO CHEN GUI 写道:
>>> Hi,
>>>   Gently ping it.
>>> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653095.html
>>>
>>> Thanks
>>> Gui Haochen
>>>
>>> 在 2024/5/30 10:46, HAO CHEN GUI 写道:
>>>> Hi,
>>>>   This patch adds the range op for builtin isnormal. It also adds two
>>>> help function in frange to detect range of normal floating-point and
>>>> range of subnormal or zero.
>>>>
>>>>   Compared to previous version, the main change is to set the range to
>>>> 1 if it's normal number otherwise to 0.
>>>> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/652221.html
>>>>
>>>>   Bootstrapped and tested on x86 and powerpc64-linux BE and LE with no
>>>> regressions. Is it OK for the trunk?
>>>>
>>>> Thanks
>>>> Gui Haochen
>>>>
>>>> ChangeLog
>>>> Value Range: Add range op for builtin isnormal
>>>>
>>>> The former patch adds optab for builtin isnormal. Thus builtin isnormal
>>>> might not be folded at front end.  So the range op for isnormal is needed
>>>> for value range analysis.  This patch adds range op for builtin isnormal.
>>>>
>>>> gcc/
>>>> 	* gimple-range-op.cc (class cfn_isfinite): New.
>>>> 	(op_cfn_finite): New variables.
>>>> 	(gimple_range_op_handler::maybe_builtin_call): Handle
>>>> 	CFN_BUILT_IN_ISFINITE.
>>>> 	* value-range.h (class frange): Declare known_isnormal and
>>>> 	known_isdenormal_or_zero.
>>>> 	(frange::known_isnormal): Define.
>>>> 	(frange::known_isdenormal_or_zero): Define.
>>>>
>>>> gcc/testsuite/
>>>> 	* gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c: New test.
>>>>
>>>> patch.diff
>>>> diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
>>>> index 5ec5c828fa4..6787f532f11 100644
>>>> --- a/gcc/gimple-range-op.cc
>>>> +++ b/gcc/gimple-range-op.cc
>>>> @@ -1289,6 +1289,61 @@ public:
>>>>    }
>>>>  } op_cfn_isfinite;
>>>>
>>>> +//Implement range operator for CFN_BUILT_IN_ISNORMAL
>>>> +class cfn_isnormal :  public range_operator
>>>> +{
>>>> +public:
>>>> +  using range_operator::fold_range;
>>>> +  using range_operator::op1_range;
>>>> +  virtual bool fold_range (irange &r, tree type, const frange &op1,
>>>> +			   const irange &, relation_trio) const override
>>>> +  {
>>>> +    if (op1.undefined_p ())
>>>> +      return false;
>>>> +
>>>> +    if (op1.known_isnormal ())
>>>> +      {
>>>> +	wide_int one = wi::one (TYPE_PRECISION (type));
>>>> +	r.set (type, one, one);
>>>> +	return true;
>>>> +      }
>>>> +
>>>> +    if (op1.known_isnan ()
>>>> +	|| op1.known_isinf ()
>>>> +	|| op1.known_isdenormal_or_zero ())
>>>> +      {
>>>> +	r.set_zero (type);
>>>> +	return true;
>>>> +      }
>>>> +
>>>> +    r.set_varying (type);
>>>> +    return true;
>>>> +  }
>>>> +  virtual bool op1_range (frange &r, tree type, const irange &lhs,
>>>> +			  const frange &, relation_trio) const override
>>>> +  {
>>>> +    if (lhs.undefined_p ())
>>>> +      return false;
>>>> +
>>>> +    if (lhs.zero_p ())
>>>> +      {
>>>> +	r.set_varying (type);
>>>> +	return true;
>>>> +      }
>>>> +
>>>> +    if (!range_includes_zero_p (lhs))
>>>> +      {
>>>> +	nan_state nan (false);
>>>> +	r.set (type, real_min_representable (type),
>>>> +	       real_max_representable (type), nan);
>>>> +	return true;
>>>> +      }
>>>> +
>>>> +    r.set_varying (type);
>>>> +    return true;
>>>> +  }
>>>> +} op_cfn_isnormal;
>>>> +
>>>>  // Implement range operator for CFN_BUILT_IN_
>>>>  class cfn_parity : public range_operator
>>>>  {
>>>> @@ -1391,6 +1446,11 @@ gimple_range_op_handler::maybe_builtin_call ()
>>>>        m_operator = &op_cfn_isfinite;
>>>>        break;
>>>>
>>>> +    case CFN_BUILT_IN_ISNORMAL:
>>>> +      m_op1 = gimple_call_arg (call, 0);
>>>> +      m_operator = &op_cfn_isnormal;
>>>> +      break;
>>>> +
>>>>      CASE_CFN_COPYSIGN_ALL:
>>>>        m_op1 = gimple_call_arg (call, 0);
>>>>        m_op2 = gimple_call_arg (call, 1);
>>>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c b/gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c
>>>> new file mode 100644
>>>> index 00000000000..c4df4d839b0
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c
>>>> @@ -0,0 +1,37 @@
>>>> +/* { dg-do compile } */
>>>> +/* { dg-options "-O2 -fdump-tree-evrp" } */
>>>> +
>>>> +#include <math.h>
>>>> +void link_error();
>>>> +
>>>> +void test1 (double x)
>>>> +{
>>>> +  if (x < __DBL_MAX__ && x > __DBL_MIN__ && !__builtin_isnormal (x))
>>>> +    link_error ();
>>>> +
>>>> +  if (x < -__DBL_MIN__ && x > -__DBL_MAX__ && !__builtin_isnormal (x))
>>>> +    link_error ();
>>>> +}
>>>> +
>>>> +void test2 (float x)
>>>> +{
>>>> +  if (x < __FLT_MAX__ && x > __FLT_MIN__ && !__builtin_isnormal (x))
>>>> +    link_error ();
>>>> +
>>>> +  if (x < -__FLT_MIN__ && x > - __FLT_MAX__ && !__builtin_isnormal (x))
>>>> +    link_error ();
>>>> +}
>>>> +
>>>> +void test3 (double x)
>>>> +{
>>>> +  if (__builtin_isnormal (x) && __builtin_isinf (x))
>>>> +    link_error ();
>>>> +}
>>>> +
>>>> +void test4 (float x)
>>>> +{
>>>> +  if (__builtin_isnormal (x) && __builtin_isinf (x))
>>>> +    link_error ();
>>>> +}
>>>> +
>>>> +/* { dg-final { scan-tree-dump-not "link_error" "evrp" } } */
>>>> diff --git a/gcc/value-range.h b/gcc/value-range.h
>>>> index 37ce91dc52d..1443d1906e5 100644
>>>> --- a/gcc/value-range.h
>>>> +++ b/gcc/value-range.h
>>>> @@ -588,6 +588,8 @@ public:
>>>>    bool maybe_isinf () const;
>>>>    bool signbit_p (bool &signbit) const;
>>>>    bool nan_signbit_p (bool &signbit) const;
>>>> +  bool known_isnormal () const;
>>>> +  bool known_isdenormal_or_zero () const;
>>>>
>>>>  protected:
>>>>    virtual bool contains_p (tree cst) const override;
>>>> @@ -1650,6 +1652,33 @@ frange::known_isfinite () const
>>>>    return (!maybe_isnan () && !real_isinf (&m_min) && !real_isinf (&m_max));
>>>>  }
>>>>
>>>> +// Return TRUE if range is known to be normal.
>>>> +
>>>> +inline bool
>>>> +frange::known_isnormal () const
>>>> +{
>>>> +  if (!known_isfinite ())
>>>> +    return false;
>>>> +
>>>> +  machine_mode mode = TYPE_MODE (type ());
>>>> +  return (!real_isdenormal (&m_min, mode) && !real_isdenormal (&m_max, mode)
>>>> +	  && !real_iszero (&m_min) && !real_iszero (&m_max)
>>>> +	  && (!real_isneg (&m_min) || real_isneg (&m_max)));
>>>> +}
>>>> +
>>>> +// Return TRUE if range is known to be denormal.
>>>> +
>>>> +inline bool
>>>> +frange::known_isdenormal_or_zero () const
>>>> +{
>>>> +  if (!known_isfinite ())
>>>> +    return false;
>>>> +
>>>> +  machine_mode mode = TYPE_MODE (type ());
>>>> +  return ((real_isdenormal (&m_min, mode) || real_iszero (&m_min))
>>>> +	  && (real_isdenormal (&m_max, mode) || real_iszero (&m_max)));
>>>> +}
>>>> +
>>>>  // Return TRUE if range may be infinite.
>>>>
>>>>  inline bool
Jeff Law Aug. 5, 2024, 3:01 p.m. UTC | #4
On 7/21/24 8:09 PM, HAO CHEN GUI wrote:
> Hi,
>    Gently ping it.
> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653095.html
Also OK.

jeff
diff mbox series

Patch

diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 5ec5c828fa4..6787f532f11 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -1289,6 +1289,61 @@  public:
   }
 } op_cfn_isfinite;

+//Implement range operator for CFN_BUILT_IN_ISNORMAL
+class cfn_isnormal :  public range_operator
+{
+public:
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  virtual bool fold_range (irange &r, tree type, const frange &op1,
+			   const irange &, relation_trio) const override
+  {
+    if (op1.undefined_p ())
+      return false;
+
+    if (op1.known_isnormal ())
+      {
+	wide_int one = wi::one (TYPE_PRECISION (type));
+	r.set (type, one, one);
+	return true;
+      }
+
+    if (op1.known_isnan ()
+	|| op1.known_isinf ()
+	|| op1.known_isdenormal_or_zero ())
+      {
+	r.set_zero (type);
+	return true;
+      }
+
+    r.set_varying (type);
+    return true;
+  }
+  virtual bool op1_range (frange &r, tree type, const irange &lhs,
+			  const frange &, relation_trio) const override
+  {
+    if (lhs.undefined_p ())
+      return false;
+
+    if (lhs.zero_p ())
+      {
+	r.set_varying (type);
+	return true;
+      }
+
+    if (!range_includes_zero_p (lhs))
+      {
+	nan_state nan (false);
+	r.set (type, real_min_representable (type),
+	       real_max_representable (type), nan);
+	return true;
+      }
+
+    r.set_varying (type);
+    return true;
+  }
+} op_cfn_isnormal;
+
 // Implement range operator for CFN_BUILT_IN_
 class cfn_parity : public range_operator
 {
@@ -1391,6 +1446,11 @@  gimple_range_op_handler::maybe_builtin_call ()
       m_operator = &op_cfn_isfinite;
       break;

+    case CFN_BUILT_IN_ISNORMAL:
+      m_op1 = gimple_call_arg (call, 0);
+      m_operator = &op_cfn_isnormal;
+      break;
+
     CASE_CFN_COPYSIGN_ALL:
       m_op1 = gimple_call_arg (call, 0);
       m_op2 = gimple_call_arg (call, 1);
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c b/gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c
new file mode 100644
index 00000000000..c4df4d839b0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c
@@ -0,0 +1,37 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+#include <math.h>
+void link_error();
+
+void test1 (double x)
+{
+  if (x < __DBL_MAX__ && x > __DBL_MIN__ && !__builtin_isnormal (x))
+    link_error ();
+
+  if (x < -__DBL_MIN__ && x > -__DBL_MAX__ && !__builtin_isnormal (x))
+    link_error ();
+}
+
+void test2 (float x)
+{
+  if (x < __FLT_MAX__ && x > __FLT_MIN__ && !__builtin_isnormal (x))
+    link_error ();
+
+  if (x < -__FLT_MIN__ && x > - __FLT_MAX__ && !__builtin_isnormal (x))
+    link_error ();
+}
+
+void test3 (double x)
+{
+  if (__builtin_isnormal (x) && __builtin_isinf (x))
+    link_error ();
+}
+
+void test4 (float x)
+{
+  if (__builtin_isnormal (x) && __builtin_isinf (x))
+    link_error ();
+}
+
+/* { dg-final { scan-tree-dump-not "link_error" "evrp" } } */
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 37ce91dc52d..1443d1906e5 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -588,6 +588,8 @@  public:
   bool maybe_isinf () const;
   bool signbit_p (bool &signbit) const;
   bool nan_signbit_p (bool &signbit) const;
+  bool known_isnormal () const;
+  bool known_isdenormal_or_zero () const;

 protected:
   virtual bool contains_p (tree cst) const override;
@@ -1650,6 +1652,33 @@  frange::known_isfinite () const
   return (!maybe_isnan () && !real_isinf (&m_min) && !real_isinf (&m_max));
 }

+// Return TRUE if range is known to be normal.
+
+inline bool
+frange::known_isnormal () const
+{
+  if (!known_isfinite ())
+    return false;
+
+  machine_mode mode = TYPE_MODE (type ());
+  return (!real_isdenormal (&m_min, mode) && !real_isdenormal (&m_max, mode)
+	  && !real_iszero (&m_min) && !real_iszero (&m_max)
+	  && (!real_isneg (&m_min) || real_isneg (&m_max)));
+}
+
+// Return TRUE if range is known to be denormal.
+
+inline bool
+frange::known_isdenormal_or_zero () const
+{
+  if (!known_isfinite ())
+    return false;
+
+  machine_mode mode = TYPE_MODE (type ());
+  return ((real_isdenormal (&m_min, mode) || real_iszero (&m_min))
+	  && (real_isdenormal (&m_max, mode) || real_iszero (&m_max)));
+}
+
 // Return TRUE if range may be infinite.

 inline bool