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] Constant fold (c1/x)*c2 as (c1*c2)/x with -ffast-math


The following patch adds two more constant folding transformations
that are only enabled with -funsafe-math-optimizations.

	(c1/x)*c2  =>  (c1*c2)/x
	c1/(x*c2)  =>  (c1/c2)/x


Whilst I was there I also tidied up some of the code in fold <RDIV_EXPR>
where we were using braces around single statements, and where we weren't
recursively calling fold after building new subexpression trees.

The following patch has been tested on i686-pc-linux-gnu with a complete
"make bootstrap", all languages except treelang, and regression tested
with a top-level "make -k check" with no new failures.

Ok for mainline?


2003-08-24  Roger Sayle  <roger@eyesopen.com>

	* fold-const.c (fold <MULT_EXPR>): Optimize (C1/X)*C2 into
	(C1*C2)/X when unsafe math optimizations are allowed.
	(fold <RDIV_EXPR>): Optimize C1/(X*C2) into (C1/C2)/X with unsafe
	math optimizations.  Minor code clean-ups.  Recursively call
	fold when constructing sub-expressions.

	* gcc.dg/20030824-1.c: New test case.


Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.297
diff -c -3 -p -r1.297 fold-const.c
*** fold-const.c	22 Aug 2003 06:45:13 -0000	1.297
--- fold-const.c	24 Aug 2003 22:55:35 -0000
*************** fold (tree expr)
*** 6060,6065 ****
--- 6060,6078 ----
  	      && real_minus_onep (arg1))
  	    return fold (build1 (NEGATE_EXPR, type, arg0));

+ 	  /* Convert (C1/X)*C2 into (C1*C2)/X.  */
+ 	  if (flag_unsafe_math_optimizations
+ 	      && TREE_CODE (arg0) == RDIV_EXPR
+ 	      && TREE_CODE (arg1) == REAL_CST
+ 	      && TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST)
+ 	    {
+ 	      tree tem = const_binop (MULT_EXPR, TREE_OPERAND (arg0, 0),
+ 				      arg1, 0);
+ 	      if (tem)
+ 		return fold (build (RDIV_EXPR, type, tem,
+ 				    TREE_OPERAND (arg0, 1)));
+ 	    }
+
  	  if (flag_unsafe_math_optimizations)
  	    {
  	      enum built_in_function fcode0 = builtin_mathfn_code (arg0);
*************** fold (tree expr)
*** 6393,6399 ****
  					  arg1, 0)))
  	    return fold (build (MULT_EXPR, type, arg0, tem));
  	  /* Find the reciprocal if optimizing and the result is exact.  */
! 	  else if (optimize)
  	    {
  	      REAL_VALUE_TYPE r;
  	      r = TREE_REAL_CST (arg1);
--- 6406,6412 ----
  					  arg1, 0)))
  	    return fold (build (MULT_EXPR, type, arg0, tem));
  	  /* Find the reciprocal if optimizing and the result is exact.  */
! 	  if (optimize)
  	    {
  	      REAL_VALUE_TYPE r;
  	      r = TREE_REAL_CST (arg1);
*************** fold (tree expr)
*** 6407,6425 ****
        /* Convert A/B/C to A/(B*C).  */
        if (flag_unsafe_math_optimizations
  	  && TREE_CODE (arg0) == RDIV_EXPR)
! 	{
! 	  return fold (build (RDIV_EXPR, type, TREE_OPERAND (arg0, 0),
! 			      build (MULT_EXPR, type, TREE_OPERAND (arg0, 1),
! 				     arg1)));
! 	}
        /* Convert A/(B/C) to (A/B)*C.  */
        if (flag_unsafe_math_optimizations
  	  && TREE_CODE (arg1) == RDIV_EXPR)
  	{
! 	  return fold (build (MULT_EXPR, type,
! 			      build (RDIV_EXPR, type, arg0,
! 				     TREE_OPERAND (arg1, 0)),
! 			      TREE_OPERAND (arg1, 1)));
  	}

        if (flag_unsafe_math_optimizations)
--- 6420,6448 ----
        /* Convert A/B/C to A/(B*C).  */
        if (flag_unsafe_math_optimizations
  	  && TREE_CODE (arg0) == RDIV_EXPR)
! 	return fold (build (RDIV_EXPR, type, TREE_OPERAND (arg0, 0),
! 			    fold (build (MULT_EXPR, type,
! 					 TREE_OPERAND (arg0, 1), arg1))));
!
        /* Convert A/(B/C) to (A/B)*C.  */
        if (flag_unsafe_math_optimizations
  	  && TREE_CODE (arg1) == RDIV_EXPR)
+ 	return fold (build (MULT_EXPR, type,
+ 			    fold (build (RDIV_EXPR, type, arg0,
+ 					 TREE_OPERAND (arg1, 0))),
+ 			    TREE_OPERAND (arg1, 1)));
+
+       /* Convert C1/(X*C2) into (C1/C2)/X.  */
+       if (flag_unsafe_math_optimizations
+ 	  && TREE_CODE (arg1) == MULT_EXPR
+ 	  && TREE_CODE (arg0) == REAL_CST
+ 	  && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST)
  	{
! 	  tree tem = const_binop (RDIV_EXPR, arg0,
! 				  TREE_OPERAND (arg1, 1), 0);
! 	  if (tem)
! 	    return fold (build (RDIV_EXPR, type, tem,
! 				TREE_OPERAND (arg1, 0)));
  	}

        if (flag_unsafe_math_optimizations)


/* Copyright (C) 2003 Free Software Foundation.

   Check that constant folding of mathematical expressions doesn't
   break anything.

   Written by Roger Sayle, 24th August 2003.  */

/* { dg-do run } */
/* { dg-options "-O2 -ffast-math" } */

void abort(void);

double foo(double x)
{
  return 12.0/(x*3.0);
}

double bar(double x)
{
  return (3.0/x)*4.0;
}

int main()
{
  if (foo(2.0) != 2.0)
    abort ();

  if (bar(2.0) != 6.0)
    abort ();

  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]