This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Avoid FP comparisons against Infinity
- From: Roger Sayle <roger at www dot eyesopen dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 18 May 2003 07:17:41 -0600 (MDT)
- Subject: [PATCH] Avoid FP comparisons against Infinity
This patch implements a suggestion of Richard Henderson's to avoid
FP comparisons against IEEE +Inf and -Inf, instead using DBL_MAX.
http://gcc.gnu.org/ml/gcc-patches/2003-03/msg01735.html
Apparently, comparing against an infinity on both the MIPS and
alpha platforms requires a emulation trap, whilst the equivalent
comparison against the maximum representable finite number, such
as DBL_MAX or FLT_MAX doesn't. Hence this speeds up MIPS and
alpha and shouldn't adversely affect any other platform.
Could someone double check the real_maxval implementation? This
appears to work correctly for IEEE representations, and I believe
that its fine for other FP formats, but its always good to have a
second opinion.
The following patch has been tested on i686-pc-linux-gnu with a
complete "make bootstrap", all languages except treelang (including
ada), and regression tested with a top-level "make -k check" with
no new failures.
Ok for mainline?
2003-05-18 Roger Sayle <roger@eyesopen.com>
* real.c (real_maxval): New function to return the largest finite
value representable in a given mode (i.e. FLT_MAX and DBL_MAX).
* real.h (real_maxval): Prototype here.
* fold-const.c (fold_inf_compare): Transform comparisons against
+-Infinity into comparisons against DBL_MAX (or equivalent).
* gcc.c-torture/execute/ieee/inf-2.c: New test case.
Index: real.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.c,v
retrieving revision 1.118
diff -c -3 -p -r1.118 real.c
*** real.c 6 May 2003 03:14:09 -0000 1.118
--- real.c 18 May 2003 01:51:49 -0000
*************** real_nan (r, str, quiet, mode)
*** 2280,2285 ****
--- 2280,2312 ----
return true;
}
+ /* Fills R with the largest finite value representable in mode MODE.
+ If SIGN is non-zero, R is set to the most negative finite value. */
+
+ void
+ real_maxval (r, sign, mode)
+ REAL_VALUE_TYPE *r;
+ int sign;
+ enum machine_mode mode;
+ {
+ const struct real_format *fmt;
+ int np2;
+
+ fmt = real_format_for_mode[mode - QFmode];
+ if (fmt == NULL)
+ abort ();
+
+ r->class = rvc_normal;
+ r->sign = sign;
+ r->signalling = 0;
+ r->canonical = 0;
+ r->exp = fmt->emax * fmt->log2_b;
+
+ np2 = SIGNIFICAND_BITS - fmt->p * fmt->log2_b;
+ memset (r->sig, -1, SIGSZ * sizeof (unsigned long));
+ clear_significand_below (r, np2);
+ }
+
/* Fills R with 2**N. */
void
Index: real.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.h,v
retrieving revision 1.65
diff -c -3 -p -r1.65 real.h
*** real.h 6 May 2003 03:14:09 -0000 1.65
--- real.h 18 May 2003 01:51:49 -0000
*************** extern void real_inf PARAMS ((REAL_VALU
*** 219,224 ****
--- 219,227 ----
extern bool real_nan PARAMS ((REAL_VALUE_TYPE *, const char *,
int, enum machine_mode));
+ extern void real_maxval PARAMS ((REAL_VALUE_TYPE *, int,
+ enum machine_mode));
+
extern void real_2expN PARAMS ((REAL_VALUE_TYPE *, int));
extern unsigned int real_hash PARAMS ((const REAL_VALUE_TYPE *));
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.251
diff -c -3 -p -r1.251 fold-const.c
*** fold-const.c 22 Apr 2003 15:01:16 -0000 1.251
--- fold-const.c 18 May 2003 01:51:59 -0000
*************** fold_inf_compare (code, type, arg0, arg1
*** 4820,4834 ****
enum tree_code code;
tree type, arg0, arg1;
{
/* For negative infinity swap the sense of the comparison. */
! if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1)))
code = swap_tree_comparison (code);
switch (code)
{
case GT_EXPR:
/* x > +Inf is always false, if with ignore sNANs. */
! if (HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))))
return NULL_TREE;
return omit_one_operand (type,
convert (type, integer_zero_node),
--- 4820,4842 ----
enum tree_code code;
tree type, arg0, arg1;
{
+ enum machine_mode mode;
+ REAL_VALUE_TYPE max;
+ tree temp;
+ bool neg;
+
+ mode = TYPE_MODE (TREE_TYPE (arg0));
+
/* For negative infinity swap the sense of the comparison. */
! neg = REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1));
! if (neg)
code = swap_tree_comparison (code);
switch (code)
{
case GT_EXPR:
/* x > +Inf is always false, if with ignore sNANs. */
! if (HONOR_SNANS (mode))
return NULL_TREE;
return omit_one_operand (type,
convert (type, integer_zero_node),
*************** fold_inf_compare (code, type, arg0, arg1
*** 4836,4842 ****
case LE_EXPR:
/* x <= +Inf is always true, if we don't case about NaNs. */
! if (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
return omit_one_operand (type,
convert (type, integer_one_node),
arg0);
--- 4844,4850 ----
case LE_EXPR:
/* x <= +Inf is always true, if we don't case about NaNs. */
! if (! HONOR_NANS (mode))
return omit_one_operand (type,
convert (type, integer_one_node),
arg0);
*************** fold_inf_compare (code, type, arg0, arg1
*** 4850,4859 ****
}
break;
! case EQ_EXPR: /* ??? x == +Inf is x > DBL_MAX */
! case GE_EXPR: /* ??? x >= +Inf is x > DBL_MAX */
! case LT_EXPR: /* ??? x < +Inf is x <= DBL_MAX */
! case NE_EXPR: /* ??? x != +Inf is !(x > DBL_MAX) */
default:
break;
--- 4858,4885 ----
}
break;
! case EQ_EXPR:
! case GE_EXPR:
! /* x == +Inf and x >= +Inf are always equal to x > DBL_MAX. */
! real_maxval (&max, neg, mode);
! return fold (build (neg ? LT_EXPR : GT_EXPR, type,
! arg0, build_real (TREE_TYPE (arg0), max)));
!
! case LT_EXPR:
! /* x < +Inf is always equal to x <= DBL_MAX. */
! real_maxval (&max, neg, mode);
! return fold (build (neg ? GE_EXPR : LE_EXPR, type,
! arg0, build_real (TREE_TYPE (arg0), max)));
!
! case NE_EXPR:
! /* x != +Inf is always equal to !(x > DBL_MAX). */
! real_maxval (&max, neg, mode);
! if (! HONOR_NANS (mode))
! return fold (build (neg ? GE_EXPR : LE_EXPR, type,
! arg0, build_real (TREE_TYPE (arg0), max)));
! temp = fold (build (neg ? LT_EXPR : GT_EXPR, type,
! arg0, build_real (TREE_TYPE (arg0), max)));
! return fold (build1 (TRUTH_NOT_EXPR, type, temp));
default:
break;
extern void abort (void);
void test(double f, double i)
{
if (f == __builtin_inf())
abort ();
if (f == -__builtin_inf())
abort ();
if (i == -__builtin_inf())
abort ();
if (i != __builtin_inf())
abort ();
if (f >= __builtin_inf())
abort ();
if (f > __builtin_inf())
abort ();
if (i > __builtin_inf())
abort ();
if (f <= -__builtin_inf())
abort ();
if (f < -__builtin_inf())
abort ();
}
void testf(float f, float i)
{
if (f == __builtin_inff())
abort ();
if (f == -__builtin_inff())
abort ();
if (i == -__builtin_inff())
abort ();
if (i != __builtin_inff())
abort ();
if (f >= __builtin_inff())
abort ();
if (f > __builtin_inff())
abort ();
if (i > __builtin_inff())
abort ();
if (f <= -__builtin_inff())
abort ();
if (f < -__builtin_inff())
abort ();
}
void testl(long double f, long double i)
{
if (f == __builtin_infl())
abort ();
if (f == -__builtin_infl())
abort ();
if (i == -__builtin_infl())
abort ();
if (i != __builtin_infl())
abort ();
if (f >= __builtin_infl())
abort ();
if (f > __builtin_infl())
abort ();
if (i > __builtin_infl())
abort ();
if (f <= -__builtin_infl())
abort ();
if (f < -__builtin_infl())
abort ();
}
int main()
{
test (34.0, __builtin_inf());
testf (34.0f, __builtin_inff());
testf (34.0l, __builtin_infl());
return 0;
}
Roger
--
Roger Sayle, E-mail: roger@eyesopen.com
OpenEye Scientific Software, WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road, Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507. Fax: (+1) 505-473-0833