On 7/11/24 1:32 AM, HAO CHEN GUI wrote:
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. It
also fixed the issue in PR114678.

   Compared with previous version, the main change is to remove xfail for
s390 in range-sincos.c and vrp-float-abs-1.c.
https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653096.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/
        PR target/114678
        * 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/
        PR target/114678
        * gcc.dg/tree-ssa/range-isinf.c: New test.
        * gcc.dg/tree-ssa/range-sincos.c: Remove xfail for s390.
        * gcc.dg/tree-ssa/vrp-float-abs-1.c: Likewise.

patch.diff
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index a80b93cf063..24559951dd6 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -1153,6 +1153,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;
+      }
So why the test for real_isinf on the upper/lower bound? If op1 is known to be a NaN, then why test the bounds at all? If a bounds test is needed, why only test the upper bound?


+  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 the result of a builtin_isinf is zero, that doesn't mean the input has a nan state. It means we know it's not infinity. The input argument could be anything but an Inf.


Jeff

Reply via email to