Patchwork [2/N] Recognize (-a * b) +- c for FMA conversion

login
register
mail settings
Submitter Richard Henderson
Date Nov. 10, 2010, 11:05 p.m.
Message ID <4CDB2522.10205@redhat.com>
Download mbox | patch
Permalink /patch/70718/
State New
Headers show

Comments

Richard Henderson - Nov. 10, 2010, 11:05 p.m.
Removes a fixme.  Required for patch 3, where -mfused-madd is removed
from the i386 port.  There are existing i386 test cases that exercise
this pattern.

Ok?


r~
From 976c37ad089d74465f1b173517138a0a047336ee Mon Sep 17 00:00:00 2001
From: Richard Henderson <rth@twiddle.net>
Date: Wed, 10 Nov 2010 13:46:01 -0800
Subject: [PATCH 2/3] Recognize -(a * b) + c -> fma(-a,b,c).

---
 gcc/tree-ssa-math-opts.c |  107 +++++++++++++++++++++++++++++++++------------
 1 files changed, 78 insertions(+), 29 deletions(-)
Richard Guenther - Nov. 11, 2010, 9:40 a.m.
On Wed, 10 Nov 2010, Richard Henderson wrote:

> Removes a fixme.  Required for patch 3, where -mfused-madd is removed
> from the i386 port.  There are existing i386 test cases that exercise
> this pattern.
> 
> Ok?

Ok.

Thanks,
Richard.

Patch

diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
index 96140f0..2840150 100644
--- a/gcc/tree-ssa-math-opts.c
+++ b/gcc/tree-ssa-math-opts.c
@@ -1503,7 +1503,7 @@  convert_mult_to_fma (gimple mul_stmt)
 {
   tree mul_result = gimple_assign_lhs (mul_stmt);
   tree type = TREE_TYPE (mul_result);
-  gimple use_stmt, fma_stmt;
+  gimple use_stmt, neguse_stmt, fma_stmt;
   use_operand_p use_p;
   imm_use_iterator imm_iter;
 
@@ -1529,17 +1529,12 @@  convert_mult_to_fma (gimple mul_stmt)
   FOR_EACH_IMM_USE_FAST (use_p, imm_iter, mul_result)
     {
       enum tree_code use_code;
+      tree result = mul_result;
+      bool negate_p = false;
+      optab opt;
 
       use_stmt = USE_STMT (use_p);
 
-      if (!is_gimple_assign (use_stmt))
-	return false;
-      use_code = gimple_assign_rhs_code (use_stmt);
-      /* ???  We need to handle NEGATE_EXPR to eventually form fnms.  */
-      if (use_code != PLUS_EXPR
-	  && use_code != MINUS_EXPR)
-	return false;
-
       /* For now restrict this operations to single basic blocks.  In theory
 	 we would want to support sinking the multiplication in
 	 m = a*b;
@@ -1552,32 +1547,82 @@  convert_mult_to_fma (gimple mul_stmt)
       if (gimple_bb (use_stmt) != gimple_bb (mul_stmt))
 	return false;
 
-      /* We can't handle a * b + a * b.  */
-      if (gimple_assign_rhs1 (use_stmt) == gimple_assign_rhs2 (use_stmt))
+      if (!is_gimple_assign (use_stmt))
 	return false;
 
-      /* If the target doesn't support a * b - c then drop the ball.  */
-      if (gimple_assign_rhs1 (use_stmt) == mul_result
-	  && use_code == MINUS_EXPR
-	  && optab_handler (fms_optab, TYPE_MODE (type)) == CODE_FOR_nothing)
-	return false;
+      use_code = gimple_assign_rhs_code (use_stmt);
+
+      /* A negate on the multiplication leads to FNMA.  */
+      if (use_code == NEGATE_EXPR)
+	{
+	  result = gimple_assign_lhs (use_stmt);
+
+	  /* Make sure the negate statement becomes dead with this
+	     single transformation.  */
+	  if (!single_imm_use (gimple_assign_lhs (use_stmt),
+			       &use_p, &neguse_stmt))
+	    return false;
+
+	  /* Re-validate.  */
+	  use_stmt = neguse_stmt;
+	  if (gimple_bb (use_stmt) != gimple_bb (mul_stmt))
+	    return false;
+	  if (!is_gimple_assign (use_stmt))
+	    return false;
+
+	  use_code = gimple_assign_rhs_code (use_stmt);
+	  negate_p = true;
+	}
 
-      /* If the target doesn't support -a * b + c then drop the ball.  */
-      if (gimple_assign_rhs2 (use_stmt) == mul_result
-	  && use_code == MINUS_EXPR
-	  && optab_handler (fnma_optab, TYPE_MODE (type)) == CODE_FOR_nothing)
+      /* Determine if the target supports the exact form we found.  */
+      switch (use_code)
+	{
+	case MINUS_EXPR:
+	  if (gimple_assign_rhs1 (use_stmt) == result)
+	    {
+	      opt = negate_p ? fnms_optab : fms_optab;
+	      break;
+	    }
+	  negate_p = !negate_p;
+	  /* FALLTHRU */
+
+	case PLUS_EXPR:
+	  opt = negate_p ? fnma_optab : fma_optab;
+	  break;
+
+	default:
+	  /* FMA can only be formed from PLUS and MINUS.  */
+	  return false;
+	}
+      if (optab_handler (opt, TYPE_MODE (type)) == CODE_FOR_nothing)
 	return false;
 
-      /* We don't yet generate -a * b - c below yet.  */
+      /* We can't handle a * b + a * b.  */
+      if (gimple_assign_rhs1 (use_stmt) == gimple_assign_rhs2 (use_stmt))
+	return false;
     }
 
   FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, mul_result)
     {
-      tree addop, mulop1;
       gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
+      enum tree_code use_code = gimple_assign_rhs_code (use_stmt);
+      tree addop, mulop1, result = mul_result;
+      bool negate_p = false;
 
-      mulop1 = gimple_assign_rhs1 (mul_stmt);
-      if (gimple_assign_rhs1 (use_stmt) == mul_result)
+      if (use_code == NEGATE_EXPR)
+	{
+	  result = gimple_assign_lhs (use_stmt);
+	  single_imm_use (gimple_assign_lhs (use_stmt), &use_p, &neguse_stmt);
+	  gsi_remove (&gsi, true);
+	  release_defs (use_stmt);
+
+	  use_stmt = neguse_stmt;
+	  gsi = gsi_for_stmt (use_stmt);
+	  use_code = gimple_assign_rhs_code (use_stmt);
+	  negate_p = true;
+	}
+
+      if (gimple_assign_rhs1 (use_stmt) == result)
 	{
 	  addop = gimple_assign_rhs2 (use_stmt);
 	  /* a * b - c -> a * b + (-c)  */
@@ -1593,13 +1638,17 @@  convert_mult_to_fma (gimple mul_stmt)
 	  addop = gimple_assign_rhs1 (use_stmt);
 	  /* a - b * c -> (-b) * c + a */
 	  if (gimple_assign_rhs_code (use_stmt) == MINUS_EXPR)
-	    mulop1 = force_gimple_operand_gsi (&gsi,
-					       build1 (NEGATE_EXPR,
-						       type, mulop1),
-					       true, NULL_TREE, true,
-					       GSI_SAME_STMT);
+	    negate_p = !negate_p;
 	}
 
+      mulop1 = gimple_assign_rhs1 (mul_stmt);
+      if (negate_p)
+	mulop1 = force_gimple_operand_gsi (&gsi,
+					   build1 (NEGATE_EXPR,
+						   type, mulop1),
+					   true, NULL_TREE, true,
+					   GSI_SAME_STMT);
+
       fma_stmt = gimple_build_assign_with_ops3 (FMA_EXPR,
 						gimple_assign_lhs (use_stmt),
 						mulop1,