diff mbox

[(4/7)] Unsigned multiplies using wider signed multiplies

Message ID 4E1C5509.6030505@codesourcery.com
State New
Headers show

Commit Message

Andrew Stubbs July 12, 2011, 2:07 p.m. UTC
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
diff mbox

Patch

2011-07-12  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.

--- /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;