mode = TYPE_MODE (TREE_TYPE (arg));
+ bool is_ibm_extended = MODE_COMPOSITE_P (mode);
+
/* If there is no optab, try generic code. */
switch (DECL_FUNCTION_CODE (fndecl))
{
{
/* isinf(x) -> isgreater(fabs(x),DBL_MAX). */
tree const isgr_fn = builtin_decl_explicit (BUILT_IN_ISGREATER);
- tree const type = TREE_TYPE (arg);
+ tree type = TREE_TYPE (arg);
REAL_VALUE_TYPE r;
char buf[128];
+ if (is_ibm_extended)
+ {
+ /* NaN and Inf are encoded in the high-order double value
+ only. The low-order value is not significant. */
+ type = double_type_node;
+ mode = DFmode;
+ arg = fold_build1_loc (loc, NOP_EXPR, type, arg);
+ }
get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
real_from_string (&r, buf);
result = build_call_expr (isgr_fn, 2,
{
/* isfinite(x) -> islessequal(fabs(x),DBL_MAX). */
tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL);
- tree const type = TREE_TYPE (arg);
+ tree type = TREE_TYPE (arg);
REAL_VALUE_TYPE r;
char buf[128];
+ if (is_ibm_extended)
+ {
+ /* NaN and Inf are encoded in the high-order double value
+ only. The low-order value is not significant. */
+ type = double_type_node;
+ mode = DFmode;
+ arg = fold_build1_loc (loc, NOP_EXPR, type, arg);
+ }
get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
real_from_string (&r, buf);
result = build_call_expr (isle_fn, 2,
/* isnormal(x) -> isgreaterequal(fabs(x),DBL_MIN) &
islessequal(fabs(x),DBL_MAX). */
tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL);
- tree const isge_fn = builtin_decl_explicit (BUILT_IN_ISGREATEREQUAL);
- tree const type = TREE_TYPE (arg);
+ tree type = TREE_TYPE (arg);
+ tree orig_arg, max_exp, min_exp;
+ machine_mode orig_mode = mode;
REAL_VALUE_TYPE rmax, rmin;
char buf[128];
+ orig_arg = arg = builtin_save_expr (arg);
+ if (is_ibm_extended)
+ {
+ /* Use double to test the normal range of IBM extended
+ precision. Emin for IBM extended precision is
+ different to emin for IEEE double, being 53 higher
+ since the low double exponent is at least 53 lower
+ than the high double exponent. */
+ type = double_type_node;
+ mode = DFmode;
+ arg = fold_build1_loc (loc, NOP_EXPR, type, arg);
+ }
+ arg = fold_build1_loc (loc, ABS_EXPR, type, arg);
+
get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
real_from_string (&rmax, buf);
- sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (mode)->emin - 1);
+ sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (orig_mode)->emin - 1);
real_from_string (&rmin, buf);
- arg = builtin_save_expr (fold_build1_loc (loc, ABS_EXPR, type, arg));
- result = build_call_expr (isle_fn, 2, arg,
- build_real (type, rmax));
- result = fold_build2 (BIT_AND_EXPR, integer_type_node, result,
- build_call_expr (isge_fn, 2, arg,
- build_real (type, rmin)));
+ max_exp = build_real (type, rmax);
+ min_exp = build_real (type, rmin);
+
+ max_exp = build_call_expr (isle_fn, 2, arg, max_exp);
+ if (is_ibm_extended)
+ {
+ /* Testing the high end of the range is done just using
+ the high double, using the same test as isfinite().
+ For the subnormal end of the range we first test the
+ high double, then if its magnitude is equal to the
+ limit of 0x1p-969, we test whether the low double is
+ non-zero and opposite sign to the high double. */
+ tree const islt_fn = builtin_decl_explicit (BUILT_IN_ISLESS);
+ tree const isgt_fn = builtin_decl_explicit (BUILT_IN_ISGREATER);
+ tree gt_min = build_call_expr (isgt_fn, 2, arg, min_exp);
+ tree eq_min = fold_build2 (EQ_EXPR, integer_type_node,
+ arg, min_exp);
+ tree as_complex = build1 (VIEW_CONVERT_EXPR,
+ complex_double_type_node, orig_arg);
+ tree hi_dbl = build1 (REALPART_EXPR, type, as_complex);
+ tree lo_dbl = build1 (IMAGPART_EXPR, type, as_complex);
+ tree zero = build_real (type, dconst0);
+ tree hilt = build_call_expr (islt_fn, 2, hi_dbl, zero);
+ tree lolt = build_call_expr (islt_fn, 2, lo_dbl, zero);
+ tree logt = build_call_expr (isgt_fn, 2, lo_dbl, zero);
+ tree ok_lo = fold_build1 (TRUTH_NOT_EXPR, integer_type_node,
+ fold_build3 (COND_EXPR,
+ integer_type_node,
+ hilt, logt, lolt));
+ eq_min = fold_build2 (TRUTH_ANDIF_EXPR, integer_type_node,
+ eq_min, ok_lo);
+ min_exp = fold_build2 (TRUTH_ORIF_EXPR, integer_type_node,
+ gt_min, eq_min);
+ }
+ else
+ {
+ tree const isge_fn
+ = builtin_decl_explicit (BUILT_IN_ISGREATEREQUAL);
+ min_exp = build_call_expr (isge_fn, 2, arg, min_exp);
+ }
+ result = fold_build2 (BIT_AND_EXPR, integer_type_node,
+ max_exp, min_exp);
return result;
}
default:
return real_isnan (&r) ? integer_one_node : integer_zero_node;
}
+ {
+ bool is_ibm_extended = MODE_COMPOSITE_P (TYPE_MODE (TREE_TYPE (arg)));
+ if (is_ibm_extended)
+ {
+ /* NaN and Inf are encoded in the high-order double value
+ only. The low-order value is not significant. */
+ arg = fold_build1_loc (loc, NOP_EXPR, double_type_node, arg);
+ }
+ }
arg = builtin_save_expr (arg);
return fold_build2_loc (loc, UNORDERED_EXPR, type, arg, arg);
--- /dev/null
+/* { dg-do run { target { powerpc*-*-linux* powerpc*-*-darwin* powerpc*-*-aix* rs6000-*-* } } } */
+/* { dg-options "-std=c99 -mlong-double-128 -O2" } */
+
+#include <float.h>
+
+union gl_long_double_union
+{
+ struct { double hi; double lo; } dd;
+ long double ld;
+};
+
+/* This is gnulib's LDBL_MAX which, being 107 bits in precision, is
+ slightly larger than gcc's 106 bit precision LDBL_MAX. */
+volatile union gl_long_double_union gl_LDBL_MAX =
+ { { DBL_MAX, DBL_MAX / (double)134217728UL / (double)134217728UL } };
+
+volatile double min_denorm = 0x1p-1074;
+volatile double ld_low = 0x1p-969;
+volatile double dinf = 1.0/0.0;
+volatile double dnan = 0.0/0.0;
+
+int
+main (void)
+{
+ long double ld;
+
+ ld = gl_LDBL_MAX.ld;
+ if (__builtin_isinfl (ld))
+ __builtin_abort ();
+ ld = -gl_LDBL_MAX.ld;
+ if (__builtin_isinfl (ld))
+ __builtin_abort ();
+
+ ld = gl_LDBL_MAX.ld;
+ if (!__builtin_isfinite (ld))
+ __builtin_abort ();
+ ld = -gl_LDBL_MAX.ld;
+ if (!__builtin_isfinite (ld))
+ __builtin_abort ();
+
+ ld = ld_low;
+ if (!__builtin_isnormal (ld))
+ __builtin_abort ();
+ ld = -ld_low;
+ if (!__builtin_isnormal (ld))
+ __builtin_abort ();
+
+ ld = -min_denorm;
+ ld += ld_low;
+ if (__builtin_isnormal (ld))
+ __builtin_abort ();
+ ld = min_denorm;
+ ld -= ld_low;
+ if (__builtin_isnormal (ld))
+ __builtin_abort ();
+
+ ld = 0.0;
+ if (__builtin_isnormal (ld))
+ __builtin_abort ();
+ ld = -0.0;
+ if (__builtin_isnormal (ld))
+ __builtin_abort ();
+
+ ld = LDBL_MAX;
+ if (!__builtin_isnormal (ld))
+ __builtin_abort ();
+ ld = -LDBL_MAX;
+ if (!__builtin_isnormal (ld))
+ __builtin_abort ();
+
+ ld = gl_LDBL_MAX.ld;
+ if (!__builtin_isnormal (ld))
+ __builtin_abort ();
+ ld = -gl_LDBL_MAX.ld;
+ if (!__builtin_isnormal (ld))
+ __builtin_abort ();
+
+ ld = dinf;
+ if (__builtin_isnormal (ld))
+ __builtin_abort ();
+ ld = -dinf;
+ if (__builtin_isnormal (ld))
+ __builtin_abort ();
+
+ ld = dnan;
+ if (__builtin_isnormal (ld))
+ __builtin_abort ();
+ ld = -dnan;
+ if (__builtin_isnormal (ld))
+ __builtin_abort ();
+ return 0;
+}