On 04/07/11 15:26, Andrew Stubbs wrote:
On 28/06/11 15:14, Andrew Stubbs wrote:
On 28/06/11 13:33, Andrew Stubbs wrote:
On 23/06/11 15:41, Andrew Stubbs wrote:
If one or both of the inputs to a widening multiply are of unsigned
type
then the compiler will attempt to use usmul_widen_optab or
umul_widen_optab, respectively.

That works fine, but only if the target supports those operations
directly. Otherwise, it just bombs out and reverts to the normal
inefficient non-widening multiply.

This patch attempts to catch these cases and use an alternative signed
widening multiply instruction, if one of those is available.

I believe this should be legal as long as the top bit of both inputs is
guaranteed to be zero. The code achieves this guarantee by
zero-extending the inputs to a wider mode (which must still be narrower
than the output mode).

OK?

This update fixes the testsuite issue Janis pointed out.

And this one fixes up the wmul-5.c testcase also. The patch has changed
the correct result.

Here's an update for the context changed by the update to patch 3.

The content of the patch has not changed.

This update does the same thing as before, but updated for the changes earlier in the patch series. In particular, the build_and_insert_cast function and find_widening_optab_handler_and_mode changes have been moved up to patch 2.

OK?

Andrew
2011-07-12  Andrew Stubbs  <a...@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.

--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/wmul-6.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv7-a" } */
+
+long long
+foo (long long a, unsigned char *b, signed char *c)
+{
+  return a + (long long)*b * (long long)*c;
+}
+
+/* { dg-final { scan-assembler "smlal" } } */
--- a/gcc/tree-ssa-math-opts.c
+++ b/gcc/tree-ssa-math-opts.c
@@ -2071,6 +2071,7 @@ convert_mult_to_widen (gimple stmt, gimple_stmt_iterator *gsi)
   enum insn_code handler;
   enum machine_mode to_mode, from_mode;
   optab op;
+  bool do_cast = false;
 
   lhs = gimple_assign_lhs (stmt);
   type = TREE_TYPE (lhs);
@@ -2094,9 +2095,32 @@ convert_mult_to_widen (gimple stmt, gimple_stmt_iterator *gsi)
 						  0, &from_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,
+							  &from_mode);
 
-  if (from_mode != TYPE_MODE (type1))
+	  if (handler == CODE_FOR_nothing)
+	    return false;
+
+	  type1 = build_nonstandard_integer_type (
+					GET_MODE_PRECISION (from_mode),
+					0);
+	  type2 = type1;
+	  do_cast = true;
+	}
+      else
+	return false;
+    }
+
+  if (from_mode != TYPE_MODE (type1) || do_cast)
     {
       location_t loc = gimple_location (stmt);
       tree tmp1, tmp2;
@@ -2143,6 +2167,7 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
   enum tree_code wmult_code;
   enum insn_code handler;
   enum machine_mode from_mode;
+  bool do_cast = false;
 
   lhs = gimple_assign_lhs (stmt);
   type = TREE_TYPE (lhs);
@@ -2234,8 +2259,21 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
   else
     return false;
 
+  /* We don't support usmadd yet, so try a wider signed mode.  */
   if (TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2))
-    return false;
+    {
+      enum machine_mode mode = TYPE_MODE (type1);
+      mode = GET_MODE_WIDER_MODE (mode);
+      if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (TYPE_MODE (type)))
+	{
+	  type1 = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
+						  0);
+	  type2 = type1;
+	  do_cast = true;
+	}
+      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.
@@ -2276,7 +2314,7 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
   if (handler == CODE_FOR_nothing)
     return false;
 
-  if (TYPE_MODE (type1) != from_mode)
+  if (TYPE_MODE (type1) != from_mode || do_cast)
     {
       location_t loc = gimple_location (stmt);
       tree tmp;

Reply via email to