tree-ssa-math-opts.c (convert_mult_to_widen): Better handle unsigned inputs of differ...
authorAndrew Stubbs <ams@codesourcery.com>
Fri, 19 Aug 2011 14:56:24 +0000 (14:56 +0000)
committerAndrew Stubbs <ams@gcc.gnu.org>
Fri, 19 Aug 2011 14:56:24 +0000 (14:56 +0000)
2011-08-19  Andrew Stubbs  <ams@codesourcery.com>

gcc/
* tree-ssa-math-opts.c (convert_mult_to_widen): Better handle
unsigned inputs of different modes.
(convert_plusminus_to_widen): Likewise.

gcc/testsuite/
* gcc.target/arm/wmul-9.c: New file.
* gcc.target/arm/wmul-bitfield-2.c: New file.

From-SVN: r177908

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arm/wmul-9.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c [new file with mode: 0644]
gcc/tree-ssa-math-opts.c

index 5cb610cc8b7b00d916ecc715f2b1447538cdf8af..648c3b1803257fadbeb4aa7988dd31abe53e159c 100644 (file)
@@ -1,3 +1,9 @@
+2011-08-19  Andrew Stubbs  <ams@codesourcery.com>
+
+       * tree-ssa-math-opts.c (convert_mult_to_widen): Better handle
+       unsigned inputs of different modes.
+       (convert_plusminus_to_widen): Likewise.
+
 2011-08-19  Andrew Stubbs  <ams@codesourcery.com>
 
        * tree-ssa-math-opts.c (is_widening_mult_rhs_p): Add new argument
index 6df6a52f609a89b9bd977204a4afe2d05416b92d..2f65d2ec57bf583c569becf277b7f13cba49b734 100644 (file)
@@ -1,3 +1,8 @@
+2011-08-19  Andrew Stubbs  <ams@codesourcery.com>
+
+       * gcc.target/arm/wmul-9.c: New file.
+       * gcc.target/arm/wmul-bitfield-2.c: New file.
+
 2011-08-19  Andrew Stubbs  <ams@codesourcery.com>
 
        * gcc.target/arm/wmul-8.c: New file.
diff --git a/gcc/testsuite/gcc.target/arm/wmul-9.c b/gcc/testsuite/gcc.target/arm/wmul-9.c
new file mode 100644 (file)
index 0000000..40ed021
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-require-effective-target arm_dsp } */
+
+long long
+foo (long long a, short *b, char *c)
+{
+  return a + *b * *c;
+}
+
+/* { dg-final { scan-assembler "smlalbb" } } */
diff --git a/gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c b/gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c
new file mode 100644 (file)
index 0000000..07ba9a8
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-require-effective-target arm_dsp } */
+
+struct bf
+{
+  int a : 3;
+  unsigned int b : 15;
+  int c : 3;
+};
+
+long long
+foo (long long a, struct bf b, struct bf c)
+{
+  return a + b.b * c.c;
+}
+
+/* { dg-final { scan-assembler "smlalbb" } } */
index bcc02b6d58eaf040162b4953d1ca8dbd6c3f817e..5ba31b560b55af503ec4fb142ffbe024e9c86f94 100644 (file)
@@ -2115,9 +2115,18 @@ convert_mult_to_widen (gimple stmt, gimple_stmt_iterator *gsi)
     {
       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;
+         /* We can use a signed multiply with unsigned types as long as
+            there is a wider mode to use, or it is the smaller of the two
+            types that is unsigned.  Note that type1 >= type2, always.  */
+         if ((TYPE_UNSIGNED (type1)
+              && TYPE_PRECISION (type1) == GET_MODE_PRECISION (from_mode))
+             || (TYPE_UNSIGNED (type2)
+                 && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode)))
+           {
+             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,
@@ -2284,14 +2293,20 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
   /* 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))
+      /* We can use a signed multiply with unsigned types as long as
+        there is a wider mode to use, or it is the smaller of the two
+        types that is unsigned.  Note that type1 >= type2, always.  */
+      if ((from_unsigned1
+          && TYPE_PRECISION (type1) == GET_MODE_PRECISION (from_mode))
+         || (from_unsigned2
+             && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode)))
        {
-         from_mode = mode;
-         from_unsigned1 = from_unsigned2 = false;
+         from_mode = GET_MODE_WIDER_MODE (from_mode);
+         if (GET_MODE_SIZE (from_mode) >= GET_MODE_SIZE (to_mode))
+           return false;
        }
-      else
-       return false;
+
+      from_unsigned1 = from_unsigned2 = false;
     }
 
   /* If there was a conversion between the multiply and addition