aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Sayle <roger@eyesopen.com>2005-12-20 04:17:58 +0000
committerRoger Sayle <sayle@gcc.gnu.org>2005-12-20 04:17:58 +0000
commitc2c22cd6345a8e6f58702c5e406fc78cd33ef959 (patch)
tree1121e7afb1420aa893aff3d3c880fafde6862df0
parentea65cd378bf9c6457a2a400e2f2fef92514d06bb (diff)
downloadgcc-c2c22cd6345a8e6f58702c5e406fc78cd33ef959.zip
gcc-c2c22cd6345a8e6f58702c5e406fc78cd33ef959.tar.gz
gcc-c2c22cd6345a8e6f58702c5e406fc78cd33ef959.tar.bz2
combine.c (try_combine): Improve splitting of binary operators by taking advantage of reassociative...
* combine.c (try_combine): Improve splitting of binary operators by taking advantage of reassociative transformations. From-SVN: r108834
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/combine.c67
2 files changed, 70 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 69bfe7a..b489083 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2005-12-19 Roger Sayle <roger@eyesopen.com>
+
+ * combine.c (try_combine): Improve splitting of binary operators
+ by taking advantage of reassociative transformations.
+
2005-12-19 Jeff Law <law@redhat.com>
* tree-ssa-dom.c (thread_across_edge): Do not use local_fold.
diff --git a/gcc/combine.c b/gcc/combine.c
index f21a17c..afbf840 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -2527,6 +2527,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
rtx newdest = i2dest;
enum rtx_code split_code = GET_CODE (*split);
enum machine_mode split_mode = GET_MODE (*split);
+ bool subst_done = false;
+ newi2pat = NULL_RTX;
/* Get NEWDEST as a register in the proper mode. We have already
validated that we can do this. */
@@ -2572,8 +2574,69 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
}
#endif
- newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
- SUBST (*split, newdest);
+ /* Attempt to split binary operators using arithmetic identities. */
+ if (BINARY_P (SET_SRC (newpat))
+ && split_mode == GET_MODE (SET_SRC (newpat))
+ && ! side_effects_p (SET_SRC (newpat)))
+ {
+ rtx setsrc = SET_SRC (newpat);
+ enum machine_mode mode = GET_MODE (setsrc);
+ enum rtx_code code = GET_CODE (setsrc);
+ rtx src_op0 = XEXP (setsrc, 0);
+ rtx src_op1 = XEXP (setsrc, 1);
+
+ /* Split "X = Y op Y" as "Z = Y; X = Z op Z". */
+ if (rtx_equal_p (src_op0, src_op1))
+ {
+ newi2pat = gen_rtx_SET (VOIDmode, newdest, src_op0);
+ SUBST (XEXP (setsrc, 0), newdest);
+ SUBST (XEXP (setsrc, 1), newdest);
+ subst_done = true;
+ }
+ /* Split "((P op Q) op R) op S" where op is PLUS or MULT. */
+ else if ((code == PLUS || code == MULT)
+ && GET_CODE (src_op0) == code
+ && GET_CODE (XEXP (src_op0, 0)) == code
+ && (INTEGRAL_MODE_P (mode)
+ || (FLOAT_MODE_P (mode)
+ && flag_unsafe_math_optimizations)))
+ {
+ rtx p = XEXP (XEXP (src_op0, 0), 0);
+ rtx q = XEXP (XEXP (src_op0, 0), 1);
+ rtx r = XEXP (src_op0, 1);
+ rtx s = src_op1;
+
+ /* Split both "((X op Y) op X) op Y" and
+ "((X op Y) op Y) op X" as "T op T" where T is
+ "X op Y". */
+ if ((rtx_equal_p (p,r) && rtx_equal_p (q,s))
+ || (rtx_equal_p (p,s) && rtx_equal_p (q,r)))
+ {
+ newi2pat = gen_rtx_SET (VOIDmode, newdest,
+ XEXP (src_op0, 0));
+ SUBST (XEXP (setsrc, 0), newdest);
+ SUBST (XEXP (setsrc, 1), newdest);
+ subst_done = true;
+ }
+ /* Split "((X op X) op Y) op Y)" as "T op T" where
+ T is "X op Y". */
+ else if (rtx_equal_p (p,q) && rtx_equal_p (r,s))
+ {
+ rtx tmp = simplify_gen_binary (code, mode, p, r);
+ newi2pat = gen_rtx_SET (VOIDmode, newdest, tmp);
+ SUBST (XEXP (setsrc, 0), newdest);
+ SUBST (XEXP (setsrc, 1), newdest);
+ subst_done = true;
+ }
+ }
+ }
+
+ if (!subst_done)
+ {
+ newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
+ SUBST (*split, newdest);
+ }
+
i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
/* recog_for_combine might have added CLOBBERs to newi2pat.