summaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-math-opts.c
diff options
context:
space:
mode:
authorbernds <bernds@138bc75d-0d04-0410-961f-82ee72b054a4>2010-06-25 08:56:24 +0000
committerbernds <bernds@138bc75d-0d04-0410-961f-82ee72b054a4>2010-06-25 08:56:24 +0000
commit00f4f70565fa903b89c2f1be5059898ddb069db0 (patch)
tree5a50f0008cf354dc460d1db0b3077d133fe49dbb /gcc/tree-ssa-math-opts.c
parent44fcaf3f4facf84f2c3d6269876bd2b80445aa32 (diff)
downloadgcc-00f4f70565fa903b89c2f1be5059898ddb069db0.tar.gz
With large parts from Jim Wilson:
PR target/43902 * tree-pretty-print.c (dump_generic_node, op_code_prio): Add WIDEN_MULT_PLUS_EXPR and WIDEN_MULT_MINUS_EXPR. * optabs.c (optab_for_tree_code): Likewise. (expand_widen_pattern_expr): Likewise. * tree-ssa-math-opts.c (convert_mult_to_widen): New function, broken out of execute_optimize_widening_mul. (convert_plusminus_to_widen): New function. (execute_optimize_widening_mul): Use the two new functions. * expr.c (expand_expr_real_2): Add support for GIMPLE_TERNARY_RHS. Remove code to generate widening multiply-accumulate. Add support for WIDEN_MULT_PLUS_EXPR and WIDEN_MULT_MINUS_EXPR. * gimple-pretty-print.c (dump_ternary_rhs): New function. (dump_gimple_assign): Call it when appropriate. * tree.def (WIDEN_MULT_PLUS_EXPR, WIDEN_MULT_MINUS_EXPR): New codes. * cfgexpand.c (gimple_assign_rhs_to_tree): Likewise. (expand_gimple_stmt_1): Likewise. (expand_debug_expr): Support WIDEN_MULT_PLUS_EXPR and WIDEN_MULT_MINUS_EXPR. * tree-ssa-operands.c (get_expr_operands): Likewise. * tree-inline.c (estimate_operator_cost): Likewise. * gimple.c (extract_ops_from_tree_1): Renamed from extract_ops_from_tree. Add new arg for a third operand; fill it. (gimple_build_assign_stat): Support operations with three operands. (gimple_build_assign_with_ops_stat): Likewise. (gimple_assign_set_rhs_from_tree): Likewise. (gimple_assign_set_rhs_with_ops_1): Renamed from gimple_assign_set_rhs_with_ops. Add new arg for a third operand. (get_gimple_rhs_num_ops): Support GIMPLE_TERNARY_RHS. (get_gimple_rhs_num_ops): Handle WIDEN_MULT_PLUS_EXPR and WIDEN_MULT_MINUS_EXPR. * gimple.h (enum gimple_rhs_class): Add GIMPLE_TERNARY_RHS. (extract_ops_from_tree_1): Adjust declaration. (gimple_assign_set_rhs_with_ops_1): Likewise. (gimple_build_assign_with_ops): Pass NULL for last operand. (gimple_build_assign_with_ops3): New macro. (gimple_assign_rhs3, gimple_assign_rhs3_ptr, gimple_assign_set_rhs3, gimple_assign_set_rhs_with_ops, extract_ops_from_tree): New inline functions. * tree-cfg.c (verify_gimple_assign_ternary): New static function. (verify_gimple_assign): Call it. * doc/gimple.texi (Manipulating operands): Document GIMPLE_TERNARY_RHS. (Tuple specific accessors, subsection GIMPLE_ASSIGN): Document new functions for dealing with three-operand statements. * tree.c (commutative_ternary_tree_code): New function. * tree.h (commutative_ternary_tree_code): Declare it. * tree-vrp.c (gimple_assign_nonnegative_warnv_p): Return false for ternary statements. (gimple_assign_nonzero_warnv_p): Likewise. * tree-ssa-sccvn.c (stmt_has_constants): Handle GIMPLE_TERNARY_RHS. * tree-ssa-ccp.c (get_rhs_assign_op_for_ccp): New static function. (ccp_fold): Use it. Handle GIMPLE_TERNARY_RHS. * tree-ssa-dom.c (enum expr_kind): Add EXPR_TERNARY. (struct hashtable_expr): New member ternary in the union. (initialize_hash_element): Handle GIMPLE_TERNARY_RHS. (hashable_expr_equal_p): Fix indentation. Handle EXPR_TERNARY. (iterative_hash_hashable_expr): Likewise. (print_expr_hash_elt): Handle EXPR_TERNARY. * gimple-fold.c (fold_gimple_assign): Handle GIMPLE_TERNARY_RHS. * tree-ssa-threadedge.c (fold_assignment_stmt): Remove useless break statements. Handle GIMPLE_TERNARY_RHS. testsuite/ PR target/43902 * gcc.target/mips/madd-9.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@161366 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-ssa-math-opts.c')
-rw-r--r--gcc/tree-ssa-math-opts.c275
1 files changed, 192 insertions, 83 deletions
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
index 9e67ea924d3..c8c64928273 100644
--- a/gcc/tree-ssa-math-opts.c
+++ b/gcc/tree-ssa-math-opts.c
@@ -1262,6 +1262,190 @@ 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. */
+
+static bool
+convert_mult_to_widen (gimple stmt)
+{
+ 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)
+ return false;
+
+ rhs1 = gimple_assign_rhs1 (stmt);
+ rhs2 = gimple_assign_rhs2 (stmt);
+
+ if (TREE_CODE (rhs1) == SSA_NAME)
+ {
+ 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))
+ return false;
+ }
+ else if (TREE_CODE (rhs1) != INTEGER_CST)
+ return false;
+
+ if (TREE_CODE (rhs2) == SSA_NAME)
+ {
+ 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))
+ return false;
+ }
+ else if (TREE_CODE (rhs2) != INTEGER_CST)
+ return false;
+
+ if (rhs1_stmt == NULL && rhs2_stmt == NULL)
+ return false;
+
+ /* 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))
+ return false;
+
+ if ((rhs1_stmt == NULL && !int_fits_type_p (rhs1, type2))
+ || (rhs2_stmt == NULL && !int_fits_type_p (rhs2, type1)))
+ return false;
+
+ if (rhs1_stmt == NULL)
+ gimple_assign_set_rhs1 (stmt, fold_convert (type2, rhs1));
+ 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);
+ gimple_assign_set_rhs_code (stmt, WIDEN_MULT_EXPR);
+ update_stmt (stmt);
+ return true;
+}
+
+/* Process a single gimple statement STMT, which is found at the
+ iterator GSI and has a either a PLUS_EXPR or a MINUS_EXPR as its
+ rhs (given by CODE), and try to convert it into a
+ WIDEN_MULT_PLUS_EXPR or a WIDEN_MULT_MINUS_EXPR. The return value
+ is true iff we converted the statement. */
+
+static bool
+convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
+ enum tree_code code)
+{
+ gimple rhs1_stmt = NULL, rhs2_stmt = NULL;
+ tree type;
+ tree lhs, rhs1, rhs2, mult_rhs1, mult_rhs2, add_rhs;
+ enum tree_code rhs1_code = ERROR_MARK, rhs2_code = ERROR_MARK;
+ optab this_optab;
+ enum tree_code wmult_code;
+
+ lhs = gimple_assign_lhs (stmt);
+ type = TREE_TYPE (lhs);
+ if (TREE_CODE (type) != INTEGER_TYPE)
+ return false;
+
+ if (code == MINUS_EXPR)
+ wmult_code = WIDEN_MULT_MINUS_EXPR;
+ else
+ wmult_code = WIDEN_MULT_PLUS_EXPR;
+
+ /* Verify that the machine can perform a widening multiply
+ 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)
+ return false;
+
+ rhs1 = gimple_assign_rhs1 (stmt);
+ rhs2 = gimple_assign_rhs2 (stmt);
+
+ if (TREE_CODE (rhs1) == SSA_NAME)
+ {
+ rhs1_stmt = SSA_NAME_DEF_STMT (rhs1);
+ if (is_gimple_assign (rhs1_stmt))
+ rhs1_code = gimple_assign_rhs_code (rhs1_stmt);
+ }
+ else
+ return false;
+
+ if (TREE_CODE (rhs2) == SSA_NAME)
+ {
+ rhs2_stmt = SSA_NAME_DEF_STMT (rhs2);
+ if (is_gimple_assign (rhs2_stmt))
+ rhs2_code = gimple_assign_rhs_code (rhs2_stmt);
+ }
+ else
+ return false;
+
+ if (rhs1_code == MULT_EXPR)
+ {
+ if (!convert_mult_to_widen (rhs1_stmt))
+ return false;
+ rhs1_code = gimple_assign_rhs_code (rhs1_stmt);
+ }
+ if (rhs2_code == MULT_EXPR)
+ {
+ if (!convert_mult_to_widen (rhs2_stmt))
+ return false;
+ rhs2_code = gimple_assign_rhs_code (rhs2_stmt);
+ }
+
+ if (code == PLUS_EXPR && rhs1_code == WIDEN_MULT_EXPR)
+ {
+ mult_rhs1 = gimple_assign_rhs1 (rhs1_stmt);
+ mult_rhs2 = gimple_assign_rhs2 (rhs1_stmt);
+ add_rhs = rhs2;
+ }
+ else if (rhs2_code == WIDEN_MULT_EXPR)
+ {
+ mult_rhs1 = gimple_assign_rhs1 (rhs2_stmt);
+ mult_rhs2 = gimple_assign_rhs2 (rhs2_stmt);
+ add_rhs = rhs1;
+ }
+ else
+ return false;
+
+ /* ??? May need some type verification here? */
+
+ gimple_assign_set_rhs_with_ops_1 (gsi, wmult_code, mult_rhs1, mult_rhs2,
+ add_rhs);
+ update_stmt (gsi_stmt (*gsi));
+ return true;
+}
+
/* Find integer multiplications where the operands are extended from
smaller types, and replace the MULT_EXPR with a WIDEN_MULT_EXPR
where appropriate. */
@@ -1279,94 +1463,19 @@ execute_optimize_widening_mul (void)
for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
- gimple rhs1_stmt = NULL, rhs2_stmt = NULL;
- tree type, type1 = NULL, type2 = NULL;
- tree rhs1, rhs2, rhs1_convop = NULL, rhs2_convop = NULL;
- enum tree_code rhs1_code, rhs2_code;
-
- if (!is_gimple_assign (stmt)
- || gimple_assign_rhs_code (stmt) != MULT_EXPR)
- continue;
-
- type = TREE_TYPE (gimple_assign_lhs (stmt));
+ enum tree_code code;
- if (TREE_CODE (type) != INTEGER_TYPE)
+ if (!is_gimple_assign (stmt))
continue;
- rhs1 = gimple_assign_rhs1 (stmt);
- rhs2 = gimple_assign_rhs2 (stmt);
-
- if (TREE_CODE (rhs1) == SSA_NAME)
- {
- rhs1_stmt = SSA_NAME_DEF_STMT (rhs1);
- if (!is_gimple_assign (rhs1_stmt))
- continue;
- rhs1_code = gimple_assign_rhs_code (rhs1_stmt);
- if (!CONVERT_EXPR_CODE_P (rhs1_code))
- continue;
- rhs1_convop = gimple_assign_rhs1 (rhs1_stmt);
- type1 = TREE_TYPE (rhs1_convop);
- if (TYPE_PRECISION (type1) * 2 != TYPE_PRECISION (type))
- continue;
- }
- else if (TREE_CODE (rhs1) != INTEGER_CST)
- continue;
-
- if (TREE_CODE (rhs2) == SSA_NAME)
- {
- rhs2_stmt = SSA_NAME_DEF_STMT (rhs2);
- if (!is_gimple_assign (rhs2_stmt))
- continue;
- rhs2_code = gimple_assign_rhs_code (rhs2_stmt);
- if (!CONVERT_EXPR_CODE_P (rhs2_code))
- continue;
- rhs2_convop = gimple_assign_rhs1 (rhs2_stmt);
- type2 = TREE_TYPE (rhs2_convop);
- if (TYPE_PRECISION (type2) * 2 != TYPE_PRECISION (type))
- continue;
- }
- else if (TREE_CODE (rhs2) != INTEGER_CST)
- continue;
-
- if (rhs1_stmt == NULL && rhs2_stmt == NULL)
- continue;
-
- /* 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))
- continue;
- 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))
- continue;
- else if (rhs1_stmt != NULL && rhs2_stmt != 0
- && (TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2))
- && (optab_handler (usmul_widen_optab, TYPE_MODE (type))
- ->insn_code == CODE_FOR_nothing))
- continue;
-
- if ((rhs1_stmt == NULL && !int_fits_type_p (rhs1, type2))
- || (rhs2_stmt == NULL && !int_fits_type_p (rhs2, type1)))
- continue;
-
- if (rhs1_stmt == NULL)
- gimple_assign_set_rhs1 (stmt, fold_convert (type2, rhs1));
- 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);
- gimple_assign_set_rhs_code (stmt, WIDEN_MULT_EXPR);
- update_stmt (stmt);
- changed = true;
+ code = gimple_assign_rhs_code (stmt);
+ if (code == MULT_EXPR)
+ changed |= convert_mult_to_widen (stmt);
+ else if (code == PLUS_EXPR || code == MINUS_EXPR)
+ changed |= convert_plusminus_to_widen (&gsi, stmt, code);
}
}
+
return (changed ? TODO_dump_func | TODO_update_ssa | TODO_verify_ssa
| TODO_verify_stmts : 0);
}