2011-06-23 Andrew Stubbs <ams@codesourcery.com>
gcc/
* tree-ssa-math-opts.c (is_widening_mult_p): Remove FIXME.
Ensure the the larger type is the first operand.
(convert_mult_to_widen): Insert cast if type2 is smaller than type1.
(convert_plusminus_to_widen): Likewise.
gcc/testsuite/
* gcc.target/arm/smlalbb-2.c: New file.
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv7-a" } */
+
+unsigned long long
+foo (unsigned long long a, unsigned char *b, unsigned short *c)
+{
+ return a + *b * *c;
+}
+
+/* { dg-final { scan-assembler "smlalbb" } } */
@@ -2051,9 +2051,17 @@ is_widening_mult_p (gimple stmt,
*type2_out = *type1_out;
}
- /* FIXME: remove this restriction. */
- if (TYPE_PRECISION (*type1_out) != TYPE_PRECISION (*type2_out))
- return false;
+ /* Ensure that the larger of the two operands comes first. */
+ if (TYPE_PRECISION (*type1_out) < TYPE_PRECISION (*type2_out))
+ {
+ tree tmp;
+ tmp = *type1_out;
+ *type1_out = *type2_out;
+ *type2_out = tmp;
+ tmp = *rhs1_out;
+ *rhs1_out = *rhs2_out;
+ *rhs2_out = tmp;
+ }
return true;
}
@@ -2069,6 +2077,7 @@ convert_mult_to_widen (gimple stmt, gimple_stmt_iterator *gsi)
enum insn_code handler;
enum machine_mode to_mode, from_mode;
optab op;
+ int cast1 = false, cast2 = false;
lhs = gimple_assign_lhs (stmt);
type = TREE_TYPE (lhs);
@@ -2107,16 +2116,26 @@ convert_mult_to_widen (gimple stmt, gimple_stmt_iterator *gsi)
return false;
type1 = type2 = lang_hooks.types.type_for_mode (from_mode, 0);
-
- rhs1 = build_and_insert_cast (gsi, gimple_location (stmt),
- create_tmp_var (type1, NULL), rhs1, type1);
- rhs2 = build_and_insert_cast (gsi, gimple_location (stmt),
- create_tmp_var (type2, NULL), rhs2, type2);
+ cast1 = cast2 = true;
}
else
return false;
}
+ if (TYPE_MODE (type2) != from_mode)
+ {
+ type2 = lang_hooks.types.type_for_mode (from_mode,
+ TYPE_UNSIGNED (type2));
+ cast2 = true;
+ }
+
+ if (cast1)
+ rhs1 = build_and_insert_cast (gsi, gimple_location (stmt),
+ create_tmp_var (type1, NULL), rhs1, type1);
+ if (cast2)
+ rhs2 = build_and_insert_cast (gsi, gimple_location (stmt),
+ create_tmp_var (type2, NULL), rhs2, type2);
+
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);
@@ -2142,6 +2161,7 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
optab this_optab;
enum tree_code wmult_code;
enum insn_code handler;
+ int cast1 = false, cast2 = false;
lhs = gimple_assign_lhs (stmt);
type = TREE_TYPE (lhs);
@@ -2228,17 +2248,28 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (TYPE_MODE (type)))
{
type1 = type2 = lang_hooks.types.type_for_mode (mode, 0);
- mult_rhs1 = build_and_insert_cast (gsi, gimple_location (stmt),
- create_tmp_var (type1, NULL),
- mult_rhs1, type1);
- mult_rhs2 = build_and_insert_cast (gsi, gimple_location (stmt),
- create_tmp_var (type2, NULL),
- mult_rhs2, type2);
+ cast1 = cast2 = true;
}
else
return false;
}
+ if (TYPE_MODE (type2) != TYPE_MODE (type1))
+ {
+ type2 = lang_hooks.types.type_for_mode (TYPE_MODE (type1),
+ TYPE_UNSIGNED (type2));
+ cast2 = true;
+ }
+
+ if (cast1)
+ mult_rhs1 = build_and_insert_cast (gsi, gimple_location (stmt),
+ create_tmp_var (type1, NULL),
+ mult_rhs1, type1);
+ if (cast2)
+ mult_rhs2 = build_and_insert_cast (gsi, gimple_location (stmt),
+ create_tmp_var (type2, NULL),
+ mult_rhs2, type2);
+
/* Verify that the machine can perform a widening multiply
accumulate in this mode/signedness combination, otherwise
this transformation is likely to pessimize code. */