Commit 1a39adae by Richard Sandiford Committed by Richard Sandiford

tree-ssa-math-opts.c (is_widening_mult_rhs_p): New function.

gcc/
	* 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.

From-SVN: r162431
parent 9362286d
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> 2010-07-22 Steven Bosscher <steven@gcc.gnu.org>
* alias.c (true_dependence_1): New function, merged version of * alias.c (true_dependence_1): New function, merged version of
......
...@@ -1260,93 +1260,127 @@ struct gimple_opt_pass pass_optimize_bswap = ...@@ -1260,93 +1260,127 @@ struct gimple_opt_pass pass_optimize_bswap =
} }
}; };
/* Process a single gimple statement STMT, which has a MULT_EXPR as /* Return true if RHS is a suitable operand for a widening multiplication.
its rhs, and try to convert it into a WIDEN_MULT_EXPR. The return There are two cases:
value is true iff we converted the statement. */
- 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 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; tree type;
type = TREE_TYPE (gimple_assign_lhs (stmt)); 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; return false;
rhs1 = gimple_assign_rhs1 (stmt); if (!is_widening_mult_rhs_p (gimple_assign_rhs2 (stmt), type2_out, rhs2_out))
rhs2 = gimple_assign_rhs2 (stmt); return false;
if (TREE_CODE (rhs1) == SSA_NAME) if (*type1_out == NULL)
{ {
rhs1_stmt = SSA_NAME_DEF_STMT (rhs1); if (*type2_out == NULL || !int_fits_type_p (*rhs1_out, *type2_out))
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))
return false; 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 (!int_fits_type_p (*rhs2_out, *type1_out))
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))
return false; return false;
*type2_out = *type1_out;
} }
else if (TREE_CODE (rhs2) != INTEGER_CST)
return false;
if (rhs1_stmt == NULL && rhs2_stmt == NULL) return true;
return false; }
/* Verify that the machine can perform a widening multiply in this /* Process a single gimple statement STMT, which has a MULT_EXPR as
mode/signedness combination, otherwise this transformation is its rhs, and try to convert it into a WIDEN_MULT_EXPR. The return
likely to pessimize code. */ value is true iff we converted the statement. */
if ((rhs1_stmt == NULL || TYPE_UNSIGNED (type1))
&& (rhs2_stmt == NULL || TYPE_UNSIGNED (type2)) static bool
&& (optab_handler (umul_widen_optab, TYPE_MODE (type)) convert_mult_to_widen (gimple stmt)
== CODE_FOR_nothing)) {
return false; tree lhs, rhs1, rhs2, type, type1, type2;
else if ((rhs1_stmt == NULL || !TYPE_UNSIGNED (type1)) enum insn_code handler;
&& (rhs2_stmt == NULL || !TYPE_UNSIGNED (type2))
&& (optab_handler (smul_widen_optab, TYPE_MODE (type)) lhs = gimple_assign_lhs (stmt);
== CODE_FOR_nothing)) type = TREE_TYPE (lhs);
return false; if (TREE_CODE (type) != INTEGER_TYPE)
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))
return false; return false;
if ((rhs1_stmt == NULL && !int_fits_type_p (rhs1, type2)) if (!is_widening_mult_p (stmt, &type1, &rhs1, &type2, &rhs2))
|| (rhs2_stmt == NULL && !int_fits_type_p (rhs2, type1)))
return false; return false;
if (rhs1_stmt == NULL) if (TYPE_UNSIGNED (type1) && TYPE_UNSIGNED (type2))
gimple_assign_set_rhs1 (stmt, fold_convert (type2, rhs1)); 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 else
gimple_assign_set_rhs1 (stmt, rhs1_convop); handler = optab_handler (usmul_widen_optab, TYPE_MODE (type));
if (rhs2_stmt == NULL)
gimple_assign_set_rhs2 (stmt, fold_convert (type1, rhs2)); if (handler == CODE_FOR_nothing)
else return false;
gimple_assign_set_rhs2 (stmt, rhs2_convop);
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); gimple_assign_set_rhs_code (stmt, WIDEN_MULT_EXPR);
update_stmt (stmt); update_stmt (stmt);
return true; return true;
...@@ -1363,7 +1397,7 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, ...@@ -1363,7 +1397,7 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
enum tree_code code) enum tree_code code)
{ {
gimple rhs1_stmt = NULL, rhs2_stmt = NULL; gimple rhs1_stmt = NULL, rhs2_stmt = NULL;
tree type; tree type, type1, type2;
tree lhs, rhs1, rhs2, mult_rhs1, mult_rhs2, add_rhs; tree lhs, rhs1, rhs2, mult_rhs1, mult_rhs2, add_rhs;
enum tree_code rhs1_code = ERROR_MARK, rhs2_code = ERROR_MARK; enum tree_code rhs1_code = ERROR_MARK, rhs2_code = ERROR_MARK;
optab this_optab; optab this_optab;
...@@ -1371,7 +1405,8 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, ...@@ -1371,7 +1405,8 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
lhs = gimple_assign_lhs (stmt); lhs = gimple_assign_lhs (stmt);
type = TREE_TYPE (lhs); type = TREE_TYPE (lhs);
if (TREE_CODE (type) != INTEGER_TYPE) if (TREE_CODE (type) != INTEGER_TYPE
&& TREE_CODE (type) != FIXED_POINT_TYPE)
return false; return false;
if (code == MINUS_EXPR) if (code == MINUS_EXPR)
...@@ -1407,20 +1442,25 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, ...@@ -1407,20 +1442,25 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
else else
return false; 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; 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; 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;
} }
else if (code == PLUS_EXPR && rhs1_code == WIDEN_MULT_EXPR)
if (code == PLUS_EXPR && rhs1_code == WIDEN_MULT_EXPR)
{ {
mult_rhs1 = gimple_assign_rhs1 (rhs1_stmt); mult_rhs1 = gimple_assign_rhs1 (rhs1_stmt);
mult_rhs2 = gimple_assign_rhs2 (rhs1_stmt); mult_rhs2 = gimple_assign_rhs2 (rhs1_stmt);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment