diff options
author | ams <ams@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-08-19 14:36:34 +0000 |
---|---|---|
committer | ams <ams@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-08-19 14:36:34 +0000 |
commit | 3f2ab71906412798529a11fbffb68348b1eb8f81 (patch) | |
tree | 34ea0aaf3a645997d9e650d4b1a93bbd16157380 /gcc/tree-ssa-math-opts.c | |
parent | 07ea3e5c6cb2d7e1178e19ba95ab1348c35e9a4b (diff) | |
download | gcc-3f2ab71906412798529a11fbffb68348b1eb8f81.tar.gz |
2011-08-19 Andrew Stubbs <ams@codesourcery.com>
gcc/
* tree-ssa-math-opts.c (convert_mult_to_widen): Convert
unsupported unsigned multiplies to signed.
(convert_plusminus_to_widen): Likewise.
gcc/testsuite/
* gcc.target/arm/wmul-6.c: New file.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@177905 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-ssa-math-opts.c')
-rw-r--r-- | gcc/tree-ssa-math-opts.c | 81 |
1 files changed, 65 insertions, 16 deletions
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c index 4bd590c33eb..0505603ed2f 100644 --- a/gcc/tree-ssa-math-opts.c +++ b/gcc/tree-ssa-math-opts.c @@ -2068,12 +2068,13 @@ is_widening_mult_p (gimple stmt, static bool convert_mult_to_widen (gimple stmt, gimple_stmt_iterator *gsi) { - tree lhs, rhs1, rhs2, type, type1, type2, tmp; + tree lhs, rhs1, rhs2, type, type1, type2, tmp = NULL; enum insn_code handler; enum machine_mode to_mode, from_mode, actual_mode; optab op; int actual_precision; location_t loc = gimple_location (stmt); + bool from_unsigned1, from_unsigned2; lhs = gimple_assign_lhs (stmt); type = TREE_TYPE (lhs); @@ -2085,10 +2086,12 @@ convert_mult_to_widen (gimple stmt, gimple_stmt_iterator *gsi) to_mode = TYPE_MODE (type); from_mode = TYPE_MODE (type1); + from_unsigned1 = TYPE_UNSIGNED (type1); + from_unsigned2 = TYPE_UNSIGNED (type2); - if (TYPE_UNSIGNED (type1) && TYPE_UNSIGNED (type2)) + if (from_unsigned1 && from_unsigned2) op = umul_widen_optab; - else if (!TYPE_UNSIGNED (type1) && !TYPE_UNSIGNED (type2)) + else if (!from_unsigned1 && !from_unsigned2) op = smul_widen_optab; else op = usmul_widen_optab; @@ -2097,22 +2100,45 @@ convert_mult_to_widen (gimple stmt, gimple_stmt_iterator *gsi) 0, &actual_mode); if (handler == CODE_FOR_nothing) - return false; + { + if (op != smul_widen_optab) + { + from_mode = GET_MODE_WIDER_MODE (from_mode); + if (GET_MODE_SIZE (to_mode) <= GET_MODE_SIZE (from_mode)) + return false; + + op = smul_widen_optab; + handler = find_widening_optab_handler_and_mode (op, to_mode, + from_mode, 0, + &actual_mode); + + if (handler == CODE_FOR_nothing) + return false; + + from_unsigned1 = from_unsigned2 = false; + } + else + return false; + } /* Ensure that the inputs to the handler are in the correct precison for the opcode. This will be the full mode size. */ actual_precision = GET_MODE_PRECISION (actual_mode); - if (actual_precision != TYPE_PRECISION (type1)) + if (actual_precision != TYPE_PRECISION (type1) + || from_unsigned1 != TYPE_UNSIGNED (type1)) { tmp = create_tmp_var (build_nonstandard_integer_type - (actual_precision, TYPE_UNSIGNED (type1)), + (actual_precision, from_unsigned1), NULL); rhs1 = build_and_insert_cast (gsi, loc, tmp, rhs1); - + } + if (actual_precision != TYPE_PRECISION (type2) + || from_unsigned2 != TYPE_UNSIGNED (type2)) + { /* Reuse the same type info, if possible. */ - if (TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2)) + if (!tmp || from_unsigned1 != from_unsigned2) tmp = create_tmp_var (build_nonstandard_integer_type - (actual_precision, TYPE_UNSIGNED (type2)), + (actual_precision, from_unsigned2), NULL); rhs2 = build_and_insert_cast (gsi, loc, tmp, rhs2); } @@ -2137,7 +2163,7 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, { gimple rhs1_stmt = NULL, rhs2_stmt = NULL; gimple conv1_stmt = NULL, conv2_stmt = NULL, conv_stmt; - tree type, type1, type2, tmp; + tree type, type1, type2, optype, tmp = NULL; tree lhs, rhs1, rhs2, mult_rhs1, mult_rhs2, add_rhs; enum tree_code rhs1_code = ERROR_MARK, rhs2_code = ERROR_MARK; optab this_optab; @@ -2146,6 +2172,7 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, enum machine_mode to_mode, from_mode, actual_mode; location_t loc = gimple_location (stmt); int actual_precision; + bool from_unsigned1, from_unsigned2; lhs = gimple_assign_lhs (stmt); type = TREE_TYPE (lhs); @@ -2239,9 +2266,21 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, to_mode = TYPE_MODE (type); from_mode = TYPE_MODE (type1); + from_unsigned1 = TYPE_UNSIGNED (type1); + from_unsigned2 = TYPE_UNSIGNED (type2); - if (TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2)) - return false; + /* There's no such thing as a mixed sign madd yet, so use a wider mode. */ + if (from_unsigned1 != from_unsigned2) + { + enum machine_mode mode = GET_MODE_WIDER_MODE (from_mode); + if (GET_MODE_PRECISION (mode) < GET_MODE_PRECISION (to_mode)) + { + from_mode = mode; + from_unsigned1 = from_unsigned2 = false; + } + else + return false; + } /* If there was a conversion between the multiply and addition then we need to make sure it fits a multiply-and-accumulate. @@ -2249,6 +2288,7 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, value. */ if (conv_stmt) { + /* We use the original, unmodified data types for this. */ tree from_type = TREE_TYPE (gimple_assign_rhs1 (conv_stmt)); tree to_type = TREE_TYPE (gimple_assign_lhs (conv_stmt)); int data_size = TYPE_PRECISION (type1) + TYPE_PRECISION (type2); @@ -2273,7 +2313,8 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, /* 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, type1, optab_default); + optype = build_nonstandard_integer_type (from_mode, from_unsigned1); + this_optab = optab_for_tree_code (wmult_code, optype, optab_default); handler = find_widening_optab_handler_and_mode (this_optab, to_mode, from_mode, 0, &actual_mode); @@ -2283,13 +2324,21 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, /* Ensure that the inputs to the handler are in the correct precison for the opcode. This will be the full mode size. */ actual_precision = GET_MODE_PRECISION (actual_mode); - if (actual_precision != TYPE_PRECISION (type1)) + if (actual_precision != TYPE_PRECISION (type1) + || from_unsigned1 != TYPE_UNSIGNED (type1)) { tmp = create_tmp_var (build_nonstandard_integer_type - (actual_precision, TYPE_UNSIGNED (type1)), + (actual_precision, from_unsigned1), NULL); - mult_rhs1 = build_and_insert_cast (gsi, loc, tmp, mult_rhs1); + } + if (actual_precision != TYPE_PRECISION (type2) + || from_unsigned2 != TYPE_UNSIGNED (type2)) + { + if (!tmp || from_unsigned1 != from_unsigned2) + tmp = create_tmp_var (build_nonstandard_integer_type + (actual_precision, from_unsigned2), + NULL); mult_rhs2 = build_and_insert_cast (gsi, loc, tmp, mult_rhs2); } |