OSDN Git Service

gcc/
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 22 Jul 2010 21:55:32 +0000 (21:55 +0000)
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 22 Jul 2010 21:55:32 +0000 (21:55 +0000)
* tree-ssa-math-opts.c (is_widening_mult_rhs_p): New function.
(is_widening_mult_p): Likewise.
(convert_to_widen): Use them.
(convert_plusminus_to_widen): Likewise.  Handle fixed-point types as
well as integer ones.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@162431 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/tree-ssa-math-opts.c

index 1086c1f..c1a4969 100644 (file)
@@ -1,3 +1,11 @@
+2010-07-22  Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * tree-ssa-math-opts.c (is_widening_mult_rhs_p): New function.
+       (is_widening_mult_p): Likewise.
+       (convert_to_widen): Use them.
+       (convert_plusminus_to_widen): Likewise.  Handle fixed-point types as
+       well as integer ones.
+
 2010-07-22  Steven Bosscher  <steven@gcc.gnu.org>
 
        * alias.c (true_dependence_1): New function, merged version of
index fe0b4f4..9b96a60 100644 (file)
@@ -1260,93 +1260,127 @@ struct gimple_opt_pass pass_optimize_bswap =
  }
 };
 
-/* Process a single gimple statement STMT, which has a MULT_EXPR as
-   its rhs, and try to convert it into a WIDEN_MULT_EXPR.  The return
-   value is true iff we converted the statement.  */
+/* Return true if RHS is a suitable operand for a widening multiplication.
+   There are two cases:
+
+     - RHS makes some value twice as wide.  Store that value in *NEW_RHS_OUT
+       if so, and store its type in *TYPE_OUT.
+
+     - RHS is an integer constant.  Store that value in *NEW_RHS_OUT if so,
+       but leave *TYPE_OUT untouched.  */
 
 static bool
-convert_mult_to_widen (gimple stmt)
+is_widening_mult_rhs_p (tree rhs, tree *type_out, tree *new_rhs_out)
+{
+  gimple stmt;
+  tree type, type1, rhs1;
+  enum tree_code rhs_code;
+
+  if (TREE_CODE (rhs) == SSA_NAME)
+    {
+      type = TREE_TYPE (rhs);
+      stmt = SSA_NAME_DEF_STMT (rhs);
+      if (!is_gimple_assign (stmt))
+       return false;
+
+      rhs_code = gimple_assign_rhs_code (stmt);
+      if (TREE_CODE (type) == INTEGER_TYPE
+         ? !CONVERT_EXPR_CODE_P (rhs_code)
+         : rhs_code != FIXED_CONVERT_EXPR)
+       return false;
+
+      rhs1 = gimple_assign_rhs1 (stmt);
+      type1 = TREE_TYPE (rhs1);
+      if (TREE_CODE (type1) != TREE_CODE (type)
+         || TYPE_PRECISION (type1) * 2 != TYPE_PRECISION (type))
+       return false;
+
+      *new_rhs_out = rhs1;
+      *type_out = type1;
+      return true;
+    }
+
+  if (TREE_CODE (rhs) == INTEGER_CST)
+    {
+      *new_rhs_out = rhs;
+      *type_out = NULL;
+      return true;
+    }
+
+  return false;
+}
+
+/* Return true if STMT performs a widening multiplication.  If so,
+   store the unwidened types of the operands in *TYPE1_OUT and *TYPE2_OUT
+   respectively.  Also fill *RHS1_OUT and *RHS2_OUT such that converting
+   those operands to types *TYPE1_OUT and *TYPE2_OUT would give the
+   operands of the multiplication.  */
+
+static bool
+is_widening_mult_p (gimple stmt,
+                   tree *type1_out, tree *rhs1_out,
+                   tree *type2_out, tree *rhs2_out)
 {
-  gimple rhs1_stmt = NULL, rhs2_stmt = NULL;
-  tree type1 = NULL, type2 = NULL;
-  tree rhs1, rhs2, rhs1_convop = NULL, rhs2_convop = NULL;
-  enum tree_code rhs1_code, rhs2_code;
   tree type;
 
   type = TREE_TYPE (gimple_assign_lhs (stmt));
+  if (TREE_CODE (type) != INTEGER_TYPE
+      && TREE_CODE (type) != FIXED_POINT_TYPE)
+    return false;
 
-  if (TREE_CODE (type) != INTEGER_TYPE)
+  if (!is_widening_mult_rhs_p (gimple_assign_rhs1 (stmt), type1_out, rhs1_out))
     return false;
 
-  rhs1 = gimple_assign_rhs1 (stmt);
-  rhs2 = gimple_assign_rhs2 (stmt);
+  if (!is_widening_mult_rhs_p (gimple_assign_rhs2 (stmt), type2_out, rhs2_out))
+    return false;
 
-  if (TREE_CODE (rhs1) == SSA_NAME)
+  if (*type1_out == NULL)
     {
-      rhs1_stmt = SSA_NAME_DEF_STMT (rhs1);
-      if (!is_gimple_assign (rhs1_stmt))
-       return false;
-      rhs1_code = gimple_assign_rhs_code (rhs1_stmt);
-      if (!CONVERT_EXPR_CODE_P (rhs1_code))
-       return false;
-      rhs1_convop = gimple_assign_rhs1 (rhs1_stmt);
-      type1 = TREE_TYPE (rhs1_convop);
-      if (TYPE_PRECISION (type1) * 2 != TYPE_PRECISION (type))
+      if (*type2_out == NULL || !int_fits_type_p (*rhs1_out, *type2_out))
        return false;
+      *type1_out = *type2_out;
     }
-  else if (TREE_CODE (rhs1) != INTEGER_CST)
-    return false;
 
-  if (TREE_CODE (rhs2) == SSA_NAME)
+  if (*type2_out == NULL)
     {
-      rhs2_stmt = SSA_NAME_DEF_STMT (rhs2);
-      if (!is_gimple_assign (rhs2_stmt))
-       return false;
-      rhs2_code = gimple_assign_rhs_code (rhs2_stmt);
-      if (!CONVERT_EXPR_CODE_P (rhs2_code))
-       return false;
-      rhs2_convop = gimple_assign_rhs1 (rhs2_stmt);
-      type2 = TREE_TYPE (rhs2_convop);
-      if (TYPE_PRECISION (type2) * 2 != TYPE_PRECISION (type))
+      if (!int_fits_type_p (*rhs2_out, *type1_out))
        return false;
+      *type2_out = *type1_out;
     }
-  else if (TREE_CODE (rhs2) != INTEGER_CST)
-    return false;
 
-  if (rhs1_stmt == NULL && rhs2_stmt == NULL)
-    return false;
+  return true;
+}
 
-  /* Verify that the machine can perform a widening multiply in this
-     mode/signedness combination, otherwise this transformation is
-     likely to pessimize code.  */
-  if ((rhs1_stmt == NULL || TYPE_UNSIGNED (type1))
-      && (rhs2_stmt == NULL || TYPE_UNSIGNED (type2))
-      && (optab_handler (umul_widen_optab, TYPE_MODE (type))
-         == CODE_FOR_nothing))
-    return false;
-  else if ((rhs1_stmt == NULL || !TYPE_UNSIGNED (type1))
-          && (rhs2_stmt == NULL || !TYPE_UNSIGNED (type2))
-          && (optab_handler (smul_widen_optab, TYPE_MODE (type))
-              == CODE_FOR_nothing))
-    return false;
-  else if (rhs1_stmt != NULL && rhs2_stmt != NULL
-          && (TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2))
-          && (optab_handler (usmul_widen_optab, TYPE_MODE (type))
-              == CODE_FOR_nothing))
+/* Process a single gimple statement STMT, which has a MULT_EXPR as
+   its rhs, and try to convert it into a WIDEN_MULT_EXPR.  The return
+   value is true iff we converted the statement.  */
+
+static bool
+convert_mult_to_widen (gimple stmt)
+{
+  tree lhs, rhs1, rhs2, type, type1, type2;
+  enum insn_code handler;
+
+  lhs = gimple_assign_lhs (stmt);
+  type = TREE_TYPE (lhs);
+  if (TREE_CODE (type) != INTEGER_TYPE)
     return false;
 
-  if ((rhs1_stmt == NULL && !int_fits_type_p (rhs1, type2))
-      || (rhs2_stmt == NULL && !int_fits_type_p (rhs2, type1)))
+  if (!is_widening_mult_p (stmt, &type1, &rhs1, &type2, &rhs2))
     return false;
 
-  if (rhs1_stmt == NULL)
-    gimple_assign_set_rhs1 (stmt, fold_convert (type2, rhs1));
+  if (TYPE_UNSIGNED (type1) && TYPE_UNSIGNED (type2))
+    handler = optab_handler (umul_widen_optab, TYPE_MODE (type));
+  else if (!TYPE_UNSIGNED (type1) && !TYPE_UNSIGNED (type2))
+    handler = optab_handler (smul_widen_optab, TYPE_MODE (type));
   else
-    gimple_assign_set_rhs1 (stmt, rhs1_convop);
-  if (rhs2_stmt == NULL)
-    gimple_assign_set_rhs2 (stmt, fold_convert (type1, rhs2));
-  else
-    gimple_assign_set_rhs2 (stmt, rhs2_convop);
+    handler = optab_handler (usmul_widen_optab, TYPE_MODE (type));
+
+  if (handler == CODE_FOR_nothing)
+    return false;
+
+  gimple_assign_set_rhs1 (stmt, fold_convert (type1, rhs1));
+  gimple_assign_set_rhs2 (stmt, fold_convert (type2, rhs2));
   gimple_assign_set_rhs_code (stmt, WIDEN_MULT_EXPR);
   update_stmt (stmt);
   return true;
@@ -1363,7 +1397,7 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
                            enum tree_code code)
 {
   gimple rhs1_stmt = NULL, rhs2_stmt = NULL;
-  tree type;
+  tree type, type1, type2;
   tree lhs, rhs1, rhs2, mult_rhs1, mult_rhs2, add_rhs;
   enum tree_code rhs1_code = ERROR_MARK, rhs2_code = ERROR_MARK;
   optab this_optab;
@@ -1371,7 +1405,8 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
 
   lhs = gimple_assign_lhs (stmt);
   type = TREE_TYPE (lhs);
-  if (TREE_CODE (type) != INTEGER_TYPE)
+  if (TREE_CODE (type) != INTEGER_TYPE
+      && TREE_CODE (type) != FIXED_POINT_TYPE)
     return false;
 
   if (code == MINUS_EXPR)
@@ -1407,20 +1442,25 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
   else
     return false;
 
-  if (rhs1_code == MULT_EXPR)
+  if (code == PLUS_EXPR && rhs1_code == MULT_EXPR)
     {
-      if (!convert_mult_to_widen (rhs1_stmt))
+      if (!is_widening_mult_p (rhs1_stmt, &type1, &mult_rhs1,
+                              &type2, &mult_rhs2))
        return false;
-      rhs1_code = gimple_assign_rhs_code (rhs1_stmt);
+      mult_rhs1 = fold_convert (type1, mult_rhs1);
+      mult_rhs2 = fold_convert (type2, mult_rhs2);
+      add_rhs = rhs2;
     }
-  if (rhs2_code == MULT_EXPR)
+  else if (rhs2_code == MULT_EXPR)
     {
-      if (!convert_mult_to_widen (rhs2_stmt))
+      if (!is_widening_mult_p (rhs1_stmt, &type1, &mult_rhs1,
+                              &type2, &mult_rhs2))
        return false;
-      rhs2_code = gimple_assign_rhs_code (rhs2_stmt);
+      mult_rhs1 = fold_convert (type1, mult_rhs1);
+      mult_rhs2 = fold_convert (type2, mult_rhs2);
+      add_rhs = rhs1;
     }
-  
-  if (code == PLUS_EXPR && rhs1_code == WIDEN_MULT_EXPR)
+  else if (code == PLUS_EXPR && rhs1_code == WIDEN_MULT_EXPR)
     {
       mult_rhs1 = gimple_assign_rhs1 (rhs1_stmt);
       mult_rhs2 = gimple_assign_rhs2 (rhs1_stmt);