summaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-math-opts.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-ssa-math-opts.c')
-rw-r--r--gcc/tree-ssa-math-opts.c197
1 files changed, 117 insertions, 80 deletions
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
index c8c64928273..9b96a608827 100644
--- a/gcc/tree-ssa-math-opts.c
+++ b/gcc/tree-ssa-math-opts.c
@@ -474,7 +474,7 @@ execute_cse_reciprocals (void)
gcc_assert (!bb->aux);
#endif
- for (arg = DECL_ARGUMENTS (cfun->decl); arg; arg = TREE_CHAIN (arg))
+ for (arg = DECL_ARGUMENTS (cfun->decl); arg; arg = DECL_CHAIN (arg))
if (gimple_default_def (cfun, arg)
&& FLOAT_TYPE_P (TREE_TYPE (arg))
&& is_gimple_reg (arg))
@@ -1113,11 +1113,9 @@ execute_optimize_bswap (void)
return 0;
bswap32_p = (built_in_decls[BUILT_IN_BSWAP32]
- && optab_handler (bswap_optab, SImode)->insn_code !=
- CODE_FOR_nothing);
+ && optab_handler (bswap_optab, SImode) != CODE_FOR_nothing);
bswap64_p = (built_in_decls[BUILT_IN_BSWAP64]
- && (optab_handler (bswap_optab, DImode)->insn_code !=
- CODE_FOR_nothing
+ && (optab_handler (bswap_optab, DImode) != CODE_FOR_nothing
|| (bswap32_p && word_mode == SImode)));
if (!bswap32_p && !bswap64_p)
@@ -1262,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))
- ->insn_code == 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))
- ->insn_code == 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))
- ->insn_code == 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;
@@ -1365,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;
@@ -1373,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)
@@ -1385,8 +1418,7 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
accumulate in this mode/signedness combination, otherwise
this transformation is likely to pessimize code. */
this_optab = optab_for_tree_code (wmult_code, type, optab_default);
- if (optab_handler (this_optab, TYPE_MODE (type))->insn_code
- == CODE_FOR_nothing)
+ if (optab_handler (this_optab, TYPE_MODE (type)) == CODE_FOR_nothing)
return false;
rhs1 = gimple_assign_rhs1 (stmt);
@@ -1410,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);