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] Canonicalize FP "X + (-C)" as "X - C"


The following patch affects how tree constant folding canonicalizes
floating point additions and subtractions of immediate constants.
For integer operations, GCC prefers to canonicalize such expressions
to always be additions by creating positive and negative constants.
The proposal is that for floating point expressions we do the reverse
and canonicalize floating point expressions such that the immediate
constant is always positive by using addition or subtraction as
appropriate.

The two motivations for this policy are (i) that many architectures
store constant floating point values in constant pools.  By attempting
to keep these values canonical, we attempt to reduce pool size, and
can reuse/CSE/GCSE these values.  And (ii) that several architectures
have instructions for efficiently loading floating point constants,
such as the x87's "fld1" instruction.  By keeping constants positive,
we get more opportunities to use these instructions.  I believe that
there are no architectures that don't provide both floating point
addition and subtraction, or where one is slower than the other.


To demonstrate (i) consider the following function:

double x, y;

void foo()
{
  x += 5.0;
  y -= 5.0;
}

Currently GCC generates the following "-O2 -fomit-frame-pointer":

.LC7:   .long   1084227584
.LC8:   .long   -1063256064

foo:    flds    .LC7
        faddl   x
        fstpl   x
        flds    .LC8
        faddl   y
        fstpl   y
        ret

With the patch below we now generate:

.LC9:   .long   1084227584

foo:    flds    .LC9
        fldl    x
        fadd    %st(1), %st
        fxch    %st(1)
        fsubrl  y
        fxch    %st(1)
        fstpl   x
        fstpl   y
        ret

which has one less memory access, and a smaller constant pool.  The
improvement is probably more obvious for rs6000 and other architectures
that can reuse this intermediate without manipulating a register stack.


To demonstrate (ii) consider the following function

double bar(double x)
{
  return x - 1.0;
}

Currently we generate the following

.LC2:   .long   -1082130432

bar:    flds    .LC2
        faddl   4(%esp)
        ret

but with the patch below we now get

bar:    fld1
        fsubrl  4(%esp)
        ret


The mechanics of the patch are straight forward, but I thought I'd
ask whether anyone's unhappy that we canonicalize integer and floating
point expressions differently.  At the moment this doesn't affect RTL
canonicalization, but clearly this change has implications there.


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

Ok for mainline?


2004-07-11  Roger Sayle  <roger@eyesopen.com>

	* fold-const.c (fold) <PLUS_EXPR>: Canonicalize X + -C as X - C for
	floating point additions, to keep real immediate constant positive.
	<MINUS_EXPR>:  For floating point subtractions, only transform X - -C
	into X + C, and leave positive real constants as X - C.


Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.421
diff -c -3 -p -r1.421 fold-const.c
*** fold-const.c	8 Jul 2004 17:40:22 -0000	1.421
--- fold-const.c	11 Jul 2004 03:48:56 -0000
*************** fold (tree expr)
*** 6589,6594 ****
--- 6589,6605 ----
  	  if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
  	    return non_lvalue (fold_convert (type, arg1));

+ 	  /* Convert X + -C into X - C.  */
+ 	  if (TREE_CODE (arg1) == REAL_CST
+ 	      && REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1)))
+ 	    {
+ 	      tem = fold_negate_const (arg1, type);
+ 	      if (!TREE_OVERFLOW (arg1) || !flag_trapping_math)
+ 		return fold (build2 (MINUS_EXPR, type,
+ 				     fold_convert (type, arg0),
+ 				     fold_convert (type, tem)));
+ 	    }
+
  	  /* Convert x+x into x*2.0.  */
  	  if (operand_equal_p (arg0, arg1, 0)
  	      && SCALAR_FLOAT_TYPE_P (type))
*************** fold (tree expr)
*** 6921,6927 ****

        /* A - B -> A + (-B) if B is easily negatable.  */
        if (!wins && negate_expr_p (arg1)
! 	  && (FLOAT_TYPE_P (type)
  	      || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv)))
  	return fold (build2 (PLUS_EXPR, type, arg0, negate_expr (arg1)));

--- 6932,6941 ----

        /* A - B -> A + (-B) if B is easily negatable.  */
        if (!wins && negate_expr_p (arg1)
! 	  && ((FLOAT_TYPE_P (type)
!              /* Avoid this transformation if B is a positive REAL_CST.  */
! 	       && (TREE_CODE (arg1) != REAL_CST
! 		   ||  REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1))))
  	      || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv)))
  	return fold (build2 (PLUS_EXPR, type, arg0, negate_expr (arg1)));


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]