This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]