summaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-math-opts.c
diff options
context:
space:
mode:
authorams <ams@138bc75d-0d04-0410-961f-82ee72b054a4>2011-08-19 14:36:34 +0000
committerams <ams@138bc75d-0d04-0410-961f-82ee72b054a4>2011-08-19 14:36:34 +0000
commit3f2ab71906412798529a11fbffb68348b1eb8f81 (patch)
tree34ea0aaf3a645997d9e650d4b1a93bbd16157380 /gcc/tree-ssa-math-opts.c
parent07ea3e5c6cb2d7e1178e19ba95ab1348c35e9a4b (diff)
downloadgcc-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.c81
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);
}