diff mbox series

[PATCH-1v3] Value Range: Add range op for builtin isinf

Message ID e51054ec-71f7-4c98-a50c-dffbe4cbc7f8@linux.ibm.com
State New
Headers show
Series [PATCH-1v3] Value Range: Add range op for builtin isinf | expand

Commit Message

HAO CHEN GUI May 30, 2024, 2:46 a.m. UTC
Hi,
  The builtin isinf is not folded at front end if the corresponding optab
exists. It causes the range evaluation failed on the targets which has
optab_isinf. For instance, range-sincos.c will fail on the targets which
has optab_isinf as it calls builtin_isinf.

  This patch fixed the problem by adding range op for builtin isinf.

  Compared with previous version, the main change is to set the range to
1 if it's infinite number otherwise to 0.
https://gcc.gnu.org/pipermail/gcc-patches/2024-May/652219.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 isinf

The builtin isinf is not folded at front end if the corresponding optab
exists.  So the range op for isinf is needed for value range analysis.
This patch adds range op for builtin isinf.

gcc/
	* gimple-range-op.cc (class cfn_isinf): New.
	(op_cfn_isinf): New variables.
	(gimple_range_op_handler::maybe_builtin_call): Handle
	CASE_FLT_FN (BUILT_IN_ISINF).

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

patch.diff

Comments

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

Thanks
Gui Haochen

在 2024/5/30 10:46, HAO CHEN GUI 写道:
> Hi,
>   The builtin isinf is not folded at front end if the corresponding optab
> exists. It causes the range evaluation failed on the targets which has
> optab_isinf. For instance, range-sincos.c will fail on the targets which
> has optab_isinf as it calls builtin_isinf.
> 
>   This patch fixed the problem by adding range op for builtin isinf.
> 
>   Compared with previous version, the main change is to set the range to
> 1 if it's infinite number otherwise to 0.
> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/652219.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 isinf
> 
> The builtin isinf is not folded at front end if the corresponding optab
> exists.  So the range op for isinf is needed for value range analysis.
> This patch adds range op for builtin isinf.
> 
> gcc/
> 	* gimple-range-op.cc (class cfn_isinf): New.
> 	(op_cfn_isinf): New variables.
> 	(gimple_range_op_handler::maybe_builtin_call): Handle
> 	CASE_FLT_FN (BUILT_IN_ISINF).
> 
> gcc/testsuite/
> 	* gcc/testsuite/gcc.dg/tree-ssa/range-isinf.c: New test.
> 
> patch.diff
> diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
> index 55dfbb23ce2..4e60a42eaac 100644
> --- a/gcc/gimple-range-op.cc
> +++ b/gcc/gimple-range-op.cc
> @@ -1175,6 +1175,63 @@ private:
>    bool m_is_pos;
>  } op_cfn_goacc_dim_size (false), op_cfn_goacc_dim_pos (true);
> 
> +// Implement range operator for CFN_BUILT_IN_ISINF
> +class cfn_isinf : 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_isinf ())
> +      {
> +	wide_int one = wi::one (TYPE_PRECISION (type));
> +	r.set (type, one, one);
> +	return true;
> +      }
> +
> +    if (op1.known_isnan ()
> +	|| (!real_isinf (&op1.lower_bound ())
> +	    && !real_isinf (&op1.upper_bound ())))
> +      {
> +	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 ())
> +      {
> +	nan_state nan (true);
> +	r.set (type, real_min_representable (type),
> +	       real_max_representable (type), nan);
> +	return true;
> +      }
> +
> +    if (!range_includes_zero_p (lhs))
> +      {
> +	// The range is [-INF,-INF][+INF,+INF], but it can't be represented.
> +	// Set range to [-INF,+INF]
> +	r.set_varying (type);
> +	r.clear_nan ();
> +	return true;
> +      }
> +
> +    r.set_varying (type);
> +    return true;
> +  }
> +} op_cfn_isinf;
> 
>  // Implement range operator for CFN_BUILT_IN_
>  class cfn_parity : public range_operator
> @@ -1268,6 +1325,11 @@ gimple_range_op_handler::maybe_builtin_call ()
>        m_operator = &op_cfn_signbit;
>        break;
> 
> +    CASE_FLT_FN (BUILT_IN_ISINF):
> +      m_op1 = gimple_call_arg (call, 0);
> +      m_operator = &op_cfn_isinf;
> +      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-isinf.c b/gcc/testsuite/gcc.dg/tree-ssa/range-isinf.c
> new file mode 100644
> index 00000000000..468f1bcf5c7
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/range-isinf.c
> @@ -0,0 +1,44 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-evrp" } */
> +
> +#include <math.h>
> +void link_error();
> +
> +void
> +test1 (double x)
> +{
> +  if (x > __DBL_MAX__ && !__builtin_isinf (x))
> +    link_error ();
> +  if (x < -__DBL_MAX__ && !__builtin_isinf (x))
> +    link_error ();
> +}
> +
> +void
> +test2 (float x)
> +{
> +  if (x > __FLT_MAX__ && !__builtin_isinf (x))
> +    link_error ();
> +  if (x < -__FLT_MAX__ && !__builtin_isinf (x))
> +    link_error ();
> +}
> +
> +void
> +test3 (double x)
> +{
> +  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x > __DBL_MAX__)
> +    link_error ();
> +  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x < -__DBL_MAX__)
> +    link_error ();
> +}
> +
> +void
> +test4 (float x)
> +{
> +  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x > __FLT_MAX__)
> +    link_error ();
> +  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x < -__FLT_MAX__)
> +    link_error ();
> +}
> +
> +/* { dg-final { scan-tree-dump-not "link_error" "evrp" } } */
> +
HAO CHEN GUI June 24, 2024, 1:40 a.m. UTC | #2
Hi,
  Gently ping it.
https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653096.html

Thanks
Gui Haochen

在 2024/6/20 14:56, HAO CHEN GUI 写道:
> Hi,
>   Gently ping it.
> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653096.html
> 
> Thanks
> Gui Haochen
> 
> 在 2024/5/30 10:46, HAO CHEN GUI 写道:
>> Hi,
>>   The builtin isinf is not folded at front end if the corresponding optab
>> exists. It causes the range evaluation failed on the targets which has
>> optab_isinf. For instance, range-sincos.c will fail on the targets which
>> has optab_isinf as it calls builtin_isinf.
>>
>>   This patch fixed the problem by adding range op for builtin isinf.
>>
>>   Compared with previous version, the main change is to set the range to
>> 1 if it's infinite number otherwise to 0.
>> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/652219.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 isinf
>>
>> The builtin isinf is not folded at front end if the corresponding optab
>> exists.  So the range op for isinf is needed for value range analysis.
>> This patch adds range op for builtin isinf.
>>
>> gcc/
>> 	* gimple-range-op.cc (class cfn_isinf): New.
>> 	(op_cfn_isinf): New variables.
>> 	(gimple_range_op_handler::maybe_builtin_call): Handle
>> 	CASE_FLT_FN (BUILT_IN_ISINF).
>>
>> gcc/testsuite/
>> 	* gcc/testsuite/gcc.dg/tree-ssa/range-isinf.c: New test.
>>
>> patch.diff
>> diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
>> index 55dfbb23ce2..4e60a42eaac 100644
>> --- a/gcc/gimple-range-op.cc
>> +++ b/gcc/gimple-range-op.cc
>> @@ -1175,6 +1175,63 @@ private:
>>    bool m_is_pos;
>>  } op_cfn_goacc_dim_size (false), op_cfn_goacc_dim_pos (true);
>>
>> +// Implement range operator for CFN_BUILT_IN_ISINF
>> +class cfn_isinf : 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_isinf ())
>> +      {
>> +	wide_int one = wi::one (TYPE_PRECISION (type));
>> +	r.set (type, one, one);
>> +	return true;
>> +      }
>> +
>> +    if (op1.known_isnan ()
>> +	|| (!real_isinf (&op1.lower_bound ())
>> +	    && !real_isinf (&op1.upper_bound ())))
>> +      {
>> +	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 ())
>> +      {
>> +	nan_state nan (true);
>> +	r.set (type, real_min_representable (type),
>> +	       real_max_representable (type), nan);
>> +	return true;
>> +      }
>> +
>> +    if (!range_includes_zero_p (lhs))
>> +      {
>> +	// The range is [-INF,-INF][+INF,+INF], but it can't be represented.
>> +	// Set range to [-INF,+INF]
>> +	r.set_varying (type);
>> +	r.clear_nan ();
>> +	return true;
>> +      }
>> +
>> +    r.set_varying (type);
>> +    return true;
>> +  }
>> +} op_cfn_isinf;
>>
>>  // Implement range operator for CFN_BUILT_IN_
>>  class cfn_parity : public range_operator
>> @@ -1268,6 +1325,11 @@ gimple_range_op_handler::maybe_builtin_call ()
>>        m_operator = &op_cfn_signbit;
>>        break;
>>
>> +    CASE_FLT_FN (BUILT_IN_ISINF):
>> +      m_op1 = gimple_call_arg (call, 0);
>> +      m_operator = &op_cfn_isinf;
>> +      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-isinf.c b/gcc/testsuite/gcc.dg/tree-ssa/range-isinf.c
>> new file mode 100644
>> index 00000000000..468f1bcf5c7
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/range-isinf.c
>> @@ -0,0 +1,44 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -fdump-tree-evrp" } */
>> +
>> +#include <math.h>
>> +void link_error();
>> +
>> +void
>> +test1 (double x)
>> +{
>> +  if (x > __DBL_MAX__ && !__builtin_isinf (x))
>> +    link_error ();
>> +  if (x < -__DBL_MAX__ && !__builtin_isinf (x))
>> +    link_error ();
>> +}
>> +
>> +void
>> +test2 (float x)
>> +{
>> +  if (x > __FLT_MAX__ && !__builtin_isinf (x))
>> +    link_error ();
>> +  if (x < -__FLT_MAX__ && !__builtin_isinf (x))
>> +    link_error ();
>> +}
>> +
>> +void
>> +test3 (double x)
>> +{
>> +  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x > __DBL_MAX__)
>> +    link_error ();
>> +  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x < -__DBL_MAX__)
>> +    link_error ();
>> +}
>> +
>> +void
>> +test4 (float x)
>> +{
>> +  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x > __FLT_MAX__)
>> +    link_error ();
>> +  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x < -__FLT_MAX__)
>> +    link_error ();
>> +}
>> +
>> +/* { dg-final { scan-tree-dump-not "link_error" "evrp" } } */
>> +
HAO CHEN GUI July 1, 2024, 1:11 a.m. UTC | #3
Hi,
  Gently ping it.
https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653096.html

Thanks
Gui Haochen

在 2024/6/24 9:40, HAO CHEN GUI 写道:
> Hi,
>   Gently ping it.
> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653096.html
> 
> Thanks
> Gui Haochen
> 
> 在 2024/6/20 14:56, HAO CHEN GUI 写道:
>> Hi,
>>   Gently ping it.
>> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653096.html
>>
>> Thanks
>> Gui Haochen
>>
>> 在 2024/5/30 10:46, HAO CHEN GUI 写道:
>>> Hi,
>>>   The builtin isinf is not folded at front end if the corresponding optab
>>> exists. It causes the range evaluation failed on the targets which has
>>> optab_isinf. For instance, range-sincos.c will fail on the targets which
>>> has optab_isinf as it calls builtin_isinf.
>>>
>>>   This patch fixed the problem by adding range op for builtin isinf.
>>>
>>>   Compared with previous version, the main change is to set the range to
>>> 1 if it's infinite number otherwise to 0.
>>> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/652219.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 isinf
>>>
>>> The builtin isinf is not folded at front end if the corresponding optab
>>> exists.  So the range op for isinf is needed for value range analysis.
>>> This patch adds range op for builtin isinf.
>>>
>>> gcc/
>>> 	* gimple-range-op.cc (class cfn_isinf): New.
>>> 	(op_cfn_isinf): New variables.
>>> 	(gimple_range_op_handler::maybe_builtin_call): Handle
>>> 	CASE_FLT_FN (BUILT_IN_ISINF).
>>>
>>> gcc/testsuite/
>>> 	* gcc/testsuite/gcc.dg/tree-ssa/range-isinf.c: New test.
>>>
>>> patch.diff
>>> diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
>>> index 55dfbb23ce2..4e60a42eaac 100644
>>> --- a/gcc/gimple-range-op.cc
>>> +++ b/gcc/gimple-range-op.cc
>>> @@ -1175,6 +1175,63 @@ private:
>>>    bool m_is_pos;
>>>  } op_cfn_goacc_dim_size (false), op_cfn_goacc_dim_pos (true);
>>>
>>> +// Implement range operator for CFN_BUILT_IN_ISINF
>>> +class cfn_isinf : 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_isinf ())
>>> +      {
>>> +	wide_int one = wi::one (TYPE_PRECISION (type));
>>> +	r.set (type, one, one);
>>> +	return true;
>>> +      }
>>> +
>>> +    if (op1.known_isnan ()
>>> +	|| (!real_isinf (&op1.lower_bound ())
>>> +	    && !real_isinf (&op1.upper_bound ())))
>>> +      {
>>> +	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 ())
>>> +      {
>>> +	nan_state nan (true);
>>> +	r.set (type, real_min_representable (type),
>>> +	       real_max_representable (type), nan);
>>> +	return true;
>>> +      }
>>> +
>>> +    if (!range_includes_zero_p (lhs))
>>> +      {
>>> +	// The range is [-INF,-INF][+INF,+INF], but it can't be represented.
>>> +	// Set range to [-INF,+INF]
>>> +	r.set_varying (type);
>>> +	r.clear_nan ();
>>> +	return true;
>>> +      }
>>> +
>>> +    r.set_varying (type);
>>> +    return true;
>>> +  }
>>> +} op_cfn_isinf;
>>>
>>>  // Implement range operator for CFN_BUILT_IN_
>>>  class cfn_parity : public range_operator
>>> @@ -1268,6 +1325,11 @@ gimple_range_op_handler::maybe_builtin_call ()
>>>        m_operator = &op_cfn_signbit;
>>>        break;
>>>
>>> +    CASE_FLT_FN (BUILT_IN_ISINF):
>>> +      m_op1 = gimple_call_arg (call, 0);
>>> +      m_operator = &op_cfn_isinf;
>>> +      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-isinf.c b/gcc/testsuite/gcc.dg/tree-ssa/range-isinf.c
>>> new file mode 100644
>>> index 00000000000..468f1bcf5c7
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/range-isinf.c
>>> @@ -0,0 +1,44 @@
>>> +/* { dg-do compile } */
>>> +/* { dg-options "-O2 -fdump-tree-evrp" } */
>>> +
>>> +#include <math.h>
>>> +void link_error();
>>> +
>>> +void
>>> +test1 (double x)
>>> +{
>>> +  if (x > __DBL_MAX__ && !__builtin_isinf (x))
>>> +    link_error ();
>>> +  if (x < -__DBL_MAX__ && !__builtin_isinf (x))
>>> +    link_error ();
>>> +}
>>> +
>>> +void
>>> +test2 (float x)
>>> +{
>>> +  if (x > __FLT_MAX__ && !__builtin_isinf (x))
>>> +    link_error ();
>>> +  if (x < -__FLT_MAX__ && !__builtin_isinf (x))
>>> +    link_error ();
>>> +}
>>> +
>>> +void
>>> +test3 (double x)
>>> +{
>>> +  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x > __DBL_MAX__)
>>> +    link_error ();
>>> +  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x < -__DBL_MAX__)
>>> +    link_error ();
>>> +}
>>> +
>>> +void
>>> +test4 (float x)
>>> +{
>>> +  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x > __FLT_MAX__)
>>> +    link_error ();
>>> +  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x < -__FLT_MAX__)
>>> +    link_error ();
>>> +}
>>> +
>>> +/* { dg-final { scan-tree-dump-not "link_error" "evrp" } } */
>>> +
Xi Ruoyao July 10, 2024, 1:54 p.m. UTC | #4
On Mon, 2024-07-01 at 09:11 +0800, HAO CHEN GUI wrote:
> Hi,
>   Gently ping it.
> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653096.html

I guess you can add PR114678 into the subject and the ChangeLog, and
also mention the patch in the bugzilla.
Xi Ruoyao July 10, 2024, 2:01 p.m. UTC | #5
On Wed, 2024-07-10 at 21:54 +0800, Xi Ruoyao wrote:
> On Mon, 2024-07-01 at 09:11 +0800, HAO CHEN GUI wrote:
> > Hi,
> >   Gently ping it.
> > https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653096.html
> 
> I guess you can add PR114678 into the subject and the ChangeLog, and
> also mention the patch in the bugzilla.

And, remove xfail in vrp-float-abs-1.c and range-sincos.c (if this patch
works as intended they should no longer fail).
HAO CHEN GUI July 11, 2024, 7:51 a.m. UTC | #6
Hi Ruoyao,
  Thanks for your info. I updated my patch and sent it for review.

Thanks
Gui Haochen

在 2024/7/10 22:01, Xi Ruoyao 写道:
> On Wed, 2024-07-10 at 21:54 +0800, Xi Ruoyao wrote:
>> On Mon, 2024-07-01 at 09:11 +0800, HAO CHEN GUI wrote:
>>> Hi,
>>>   Gently ping it.
>>> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653096.html
>>
>> I guess you can add PR114678 into the subject and the ChangeLog, and
>> also mention the patch in the bugzilla.
> 
> And, remove xfail in vrp-float-abs-1.c and range-sincos.c (if this patch
> works as intended they should no longer fail).
>
diff mbox series

Patch

diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 55dfbb23ce2..4e60a42eaac 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -1175,6 +1175,63 @@  private:
   bool m_is_pos;
 } op_cfn_goacc_dim_size (false), op_cfn_goacc_dim_pos (true);

+// Implement range operator for CFN_BUILT_IN_ISINF
+class cfn_isinf : 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_isinf ())
+      {
+	wide_int one = wi::one (TYPE_PRECISION (type));
+	r.set (type, one, one);
+	return true;
+      }
+
+    if (op1.known_isnan ()
+	|| (!real_isinf (&op1.lower_bound ())
+	    && !real_isinf (&op1.upper_bound ())))
+      {
+	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 ())
+      {
+	nan_state nan (true);
+	r.set (type, real_min_representable (type),
+	       real_max_representable (type), nan);
+	return true;
+      }
+
+    if (!range_includes_zero_p (lhs))
+      {
+	// The range is [-INF,-INF][+INF,+INF], but it can't be represented.
+	// Set range to [-INF,+INF]
+	r.set_varying (type);
+	r.clear_nan ();
+	return true;
+      }
+
+    r.set_varying (type);
+    return true;
+  }
+} op_cfn_isinf;

 // Implement range operator for CFN_BUILT_IN_
 class cfn_parity : public range_operator
@@ -1268,6 +1325,11 @@  gimple_range_op_handler::maybe_builtin_call ()
       m_operator = &op_cfn_signbit;
       break;

+    CASE_FLT_FN (BUILT_IN_ISINF):
+      m_op1 = gimple_call_arg (call, 0);
+      m_operator = &op_cfn_isinf;
+      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-isinf.c b/gcc/testsuite/gcc.dg/tree-ssa/range-isinf.c
new file mode 100644
index 00000000000..468f1bcf5c7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/range-isinf.c
@@ -0,0 +1,44 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+#include <math.h>
+void link_error();
+
+void
+test1 (double x)
+{
+  if (x > __DBL_MAX__ && !__builtin_isinf (x))
+    link_error ();
+  if (x < -__DBL_MAX__ && !__builtin_isinf (x))
+    link_error ();
+}
+
+void
+test2 (float x)
+{
+  if (x > __FLT_MAX__ && !__builtin_isinf (x))
+    link_error ();
+  if (x < -__FLT_MAX__ && !__builtin_isinf (x))
+    link_error ();
+}
+
+void
+test3 (double x)
+{
+  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x > __DBL_MAX__)
+    link_error ();
+  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x < -__DBL_MAX__)
+    link_error ();
+}
+
+void
+test4 (float x)
+{
+  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x > __FLT_MAX__)
+    link_error ();
+  if (!__builtin_isinf (x) && !__builtin_isnan (x) && x < -__FLT_MAX__)
+    link_error ();
+}
+
+/* { dg-final { scan-tree-dump-not "link_error" "evrp" } } */
+