aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaochen Gui <guihaoc@gcc.gnu.org>2024-08-15 11:21:08 +0800
committerHaochen Gui <guihaoc@gcc.gnu.org>2024-08-15 11:27:11 +0800
commitd2e90c7d65749a02a20aca717ac47d02ef0b5d81 (patch)
treec4b9e7cc1f4ee06badcda65b8c777bc4c3dee8a1
parentb1d21582bafa1954db3a62f0972ae3a2e3bc0b48 (diff)
downloadgcc-d2e90c7d65749a02a20aca717ac47d02ef0b5d81.zip
gcc-d2e90c7d65749a02a20aca717ac47d02ef0b5d81.tar.gz
gcc-d2e90c7d65749a02a20aca717ac47d02ef0b5d81.tar.bz2
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): Declear known_isnormal and known_isdenormal_or_zero. (frange::known_isnormal): Define. (frange::known_isdenormal_or_zero): Define. gcc/testsuite/ * gcc.dg/tree-ssa/range-isnormal.c: New test.
-rw-r--r--gcc/gimple-range-op.cc60
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/range-isnormal.c37
-rw-r--r--gcc/value-range.h29
3 files changed, 126 insertions, 0 deletions
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 7edfa8e..d1c5271 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -1267,6 +1267,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
{
@@ -1369,6 +1424,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 0000000..c4df4d8
--- /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 03af758..ff63d4f 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;
@@ -1648,6 +1650,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