This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Optimize -1.0*x into -x
- From: Roger Sayle <roger at eyesopen dot com>
- To: <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 23 May 2002 18:31:53 -0600 (MDT)
- Subject: [PATCH] Optimize -1.0*x into -x
The following patch transforms the floating point multiplication
-1.0 * x into the equivalent -x. This allows use of the faster
floating point negation instructions, e.g. fchs on x86. I believe
that this transformation is always valid for IEEE math, including
NaNs, infinities and signed zeros, but I thought I'd get a second
opinion from the reviewer/FP lawyers. In the meantime, I've left
this optimization only enabled for -ffast-math. This code also
optimizes the x/-1.0 case, as the division by constant is turned
into the appropriate multiplication with -ffast-math.
Tested with a complete "make bootstrap" and "make -k check" on
i686-pc-linux-gnu, all languages except Ada, without any new
regressions. I've also included a "correctness" test case to
check that nothing strange is happening.
Ok for mainline?
2002-05-23 Roger Sayle <roger@eyesopen.com>
* tree.c (real_minus_onep): New function to test for -1.0.
* fold-const.c (fold) [MULT_EXPR]: Optimize -1.0*x into -x.
* gcc.dg/fnegate-1.c: New test case.
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.337
diff -c -3 -p -r1.337 tree.h
*** tree.h 22 May 2002 01:11:17 -0000 1.337
--- tree.h 23 May 2002 22:24:15 -0000
*************** extern void expand_pending_sizes
*** 2852,2857 ****
--- 2852,2858 ----
extern int real_onep PARAMS ((tree));
extern int real_twop PARAMS ((tree));
+ extern int real_minus_onep PARAMS ((tree));
extern void gcc_obstack_init PARAMS ((struct obstack *));
extern void init_obstacks PARAMS ((void));
extern void build_common_tree_nodes PARAMS ((int));
Index: tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.258
diff -c -3 -p -r1.258 tree.c
*** tree.c 22 May 2002 01:11:17 -0000 1.258
--- tree.c 23 May 2002 22:24:16 -0000
*************** real_twop (expr)
*** 896,901 ****
--- 896,917 ----
&& real_zerop (TREE_IMAGPART (expr))));
}
+ /* Return 1 if EXPR is the real constant minus one. */
+
+ int
+ real_minus_onep (expr)
+ tree expr;
+ {
+ STRIP_NOPS (expr);
+
+ return ((TREE_CODE (expr) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (expr)
+ && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconstm1))
+ || (TREE_CODE (expr) == COMPLEX_CST
+ && real_minus_onep (TREE_REALPART (expr))
+ && real_zerop (TREE_IMAGPART (expr))));
+ }
+
/* Nonzero if EXP is a constant or a cast of a constant. */
int
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.203
diff -c -3 -p -r1.203 fold-const.c
*** fold-const.c 17 May 2002 18:07:00 -0000 1.203
--- fold-const.c 23 May 2002 22:24:18 -0000
*************** fold (expr)
*** 5346,5351 ****
--- 5346,5359 ----
so we can do this anyway. */
if (real_onep (arg1))
return non_lvalue (convert (type, arg0));
+
+ /* Transform x * -1.0 into -x. This should be safe for NaNs,
+ signed zeros and signed infinities, but is currently
+ restricted to "unsafe math optimizations" just in case. */
+ if (flag_unsafe_math_optimizations
+ && real_minus_onep (arg1))
+ return fold (build1 (NEGATE_EXPR, type, arg0));
+
/* x*2 is x+x */
if (! wins && real_twop (arg1)
&& (*lang_hooks.decls.global_bindings_p) () == 0
*** /dev/null Thu Aug 30 14:30:55 2001
--- gcc.dg/fnegate-1.c Thu May 23 18:24:44 2002
***************
*** 0 ****
--- 1,113 ----
+ /* Copyright (C) 2002 Free Software Foundation.
+
+ Test floating point negation produces the expected results.
+
+ Written by Roger Sayle, 21st May 2002. */
+
+ /* { dg-do run } */
+ /* { dg-options "-O2 -ffast-math" } */
+
+ extern void abort ();
+
+
+ double
+ dneg (double x)
+ {
+ return -x;
+ }
+
+ double
+ dmult (double x)
+ {
+ return -1.0 * x;
+ }
+
+ double
+ ddiv (double x)
+ {
+ return x / -1.0;
+ }
+
+
+ float
+ fneg (float x)
+ {
+ return -x;
+ }
+
+ float
+ fmult (float x)
+ {
+ return -1.0f * x;
+ }
+
+ float
+ fdiv (float x)
+ {
+ return x / -1.0f;
+ }
+
+
+ void
+ ftest(float src, float dst)
+ {
+ if (fneg (src) != dst)
+ abort ();
+
+ if (src != fneg (dst))
+ abort ();
+
+ if (fmult (src) != dst)
+ abort ();
+
+ if (src != fmult (dst))
+ abort ();
+
+ if (fdiv (src) != dst)
+ abort ();
+
+ if (src != fdiv(dst))
+ abort ();
+ }
+
+ void
+ dtest(double src, double dst)
+ {
+ if (dneg (src) != dst)
+ abort ();
+
+ if (src != dneg (dst))
+ abort ();
+
+ if (dmult (src) != dst)
+ abort ();
+
+ if (src != dmult (dst))
+ abort ();
+
+ if (ddiv (src) != dst)
+ abort ();
+
+ if (src != ddiv(dst))
+ abort ();
+ }
+
+
+ int
+ main ()
+ {
+ ftest (1.0f, -1.0f);
+ ftest (2.0f, -2.0f);
+ ftest (-3.0f, 3.0f);
+ ftest (0.0f, -0.0f);
+ ftest (-0.0f, 0.0f);
+
+ dtest (1.0, -1.0);
+ dtest (2.0, -2.0);
+ dtest (-3.0, 3.0);
+ dtest (0.0, -0.0);
+ dtest (-0.0, 0.0);
+
+ 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