@@ -1281,6 +1281,60 @@ 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 ())
+ {
+ r.set_nonzero (type);
+ 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
{
@@ -1383,6 +1437,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);
new file mode 100644
@@ -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" } } */
@@ -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