OSDN Git Service

2011-08-19 Andrew Stubbs <ams@codesourcery.com>
authorams <ams@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 19 Aug 2011 14:31:30 +0000 (14:31 +0000)
committerams <ams@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 19 Aug 2011 14:31:30 +0000 (14:31 +0000)
gcc/
* tree-ssa-math-opts.c (convert_plusminus_to_widen): Permit a single
conversion statement separating multiply-and-accumulate.

gcc/testsuite/
* gcc.target/arm/wmul-5.c: New file.
* gcc.target/arm/no-wmla-1.c: New file.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@177904 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arm/no-wmla-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/wmul-5.c [new file with mode: 0644]
gcc/tree-ssa-math-opts.c

index 74b58ff..65d81c9 100644 (file)
@@ -1,3 +1,8 @@
+2011-08-19  Andrew Stubbs  <ams@codesourcery.com>
+
+       * tree-ssa-math-opts.c (convert_plusminus_to_widen): Permit a single
+       conversion statement separating multiply-and-accumulate.
+
 2011-08-19  Richard Guenther  <rguenther@suse.de>
 
        PR tree-optimization/50067
index 139969f..d17dcac 100644 (file)
@@ -1,5 +1,10 @@
 2011-08-19  Andrew Stubbs  <ams@codesourcery.com>
 
+       * gcc.target/arm/wmul-5.c: New file.
+       * gcc.target/arm/no-wmla-1.c: New file.
+
+2011-08-19  Andrew Stubbs  <ams@codesourcery.com>
+
        * gcc.target/arm/wmul-bitfield-1.c: New file.
 
 2011-08-19  Joseph Myers  <joseph@codesourcery.com>
diff --git a/gcc/testsuite/gcc.target/arm/no-wmla-1.c b/gcc/testsuite/gcc.target/arm/no-wmla-1.c
new file mode 100644 (file)
index 0000000..1be162e
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-require-effective-target arm_dsp } */
+
+int
+foo (int a, short b, short c)
+{
+     int bc = b * c;
+        return a + (short)bc;
+}
+
+/* { dg-final { scan-assembler "\tmul\t" } } */
diff --git a/gcc/testsuite/gcc.target/arm/wmul-5.c b/gcc/testsuite/gcc.target/arm/wmul-5.c
new file mode 100644 (file)
index 0000000..9f29a81
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-require-effective-target arm_dsp } */
+
+long long
+foo (long long a, char *b, char *c)
+{
+  return a + *b * *c;
+}
+
+/* { dg-final { scan-assembler "umlal" } } */
index 2e3781e..4bd590c 100644 (file)
@@ -2136,6 +2136,7 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
                            enum tree_code code)
 {
   gimple rhs1_stmt = NULL, rhs2_stmt = NULL;
+  gimple conv1_stmt = NULL, conv2_stmt = NULL, conv_stmt;
   tree type, type1, type2, tmp;
   tree lhs, rhs1, rhs2, mult_rhs1, mult_rhs2, add_rhs;
   enum tree_code rhs1_code = ERROR_MARK, rhs2_code = ERROR_MARK;
@@ -2178,6 +2179,38 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
   else
     return false;
 
+  /* Allow for one conversion statement between the multiply
+     and addition/subtraction statement.  If there are more than
+     one conversions then we assume they would invalidate this
+     transformation.  If that's not the case then they should have
+     been folded before now.  */
+  if (CONVERT_EXPR_CODE_P (rhs1_code))
+    {
+      conv1_stmt = rhs1_stmt;
+      rhs1 = gimple_assign_rhs1 (rhs1_stmt);
+      if (TREE_CODE (rhs1) == SSA_NAME)
+       {
+         rhs1_stmt = SSA_NAME_DEF_STMT (rhs1);
+         if (is_gimple_assign (rhs1_stmt))
+           rhs1_code = gimple_assign_rhs_code (rhs1_stmt);
+       }
+      else
+       return false;
+    }
+  if (CONVERT_EXPR_CODE_P (rhs2_code))
+    {
+      conv2_stmt = rhs2_stmt;
+      rhs2 = gimple_assign_rhs1 (rhs2_stmt);
+      if (TREE_CODE (rhs2) == SSA_NAME)
+       {
+         rhs2_stmt = SSA_NAME_DEF_STMT (rhs2);
+         if (is_gimple_assign (rhs2_stmt))
+           rhs2_code = gimple_assign_rhs_code (rhs2_stmt);
+       }
+      else
+       return false;
+    }
+
   /* If code is WIDEN_MULT_EXPR then it would seem unnecessary to call
      is_widening_mult_p, but we still need the rhs returns.
 
@@ -2191,6 +2224,7 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
                               &type2, &mult_rhs2))
        return false;
       add_rhs = rhs2;
+      conv_stmt = conv1_stmt;
     }
   else if (rhs2_code == MULT_EXPR || rhs2_code == WIDEN_MULT_EXPR)
     {
@@ -2198,6 +2232,7 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
                               &type2, &mult_rhs2))
        return false;
       add_rhs = rhs1;
+      conv_stmt = conv2_stmt;
     }
   else
     return false;
@@ -2208,6 +2243,33 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt,
   if (TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2))
     return false;
 
+  /* If there was a conversion between the multiply and addition
+     then we need to make sure it fits a multiply-and-accumulate.
+     The should be a single mode change which does not change the
+     value.  */
+  if (conv_stmt)
+    {
+      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);
+      bool is_unsigned = TYPE_UNSIGNED (type1) && TYPE_UNSIGNED (type2);
+
+      if (TYPE_PRECISION (from_type) > TYPE_PRECISION (to_type))
+       {
+         /* Conversion is a truncate.  */
+         if (TYPE_PRECISION (to_type) < data_size)
+           return false;
+       }
+      else if (TYPE_PRECISION (from_type) < TYPE_PRECISION (to_type))
+       {
+         /* Conversion is an extend.  Check it's the right sort.  */
+         if (TYPE_UNSIGNED (from_type) != is_unsigned
+             && !(is_unsigned && TYPE_PRECISION (from_type) > data_size))
+           return false;
+       }
+      /* else convert is a no-op for our purposes.  */
+    }
+
   /* Verify that the machine can perform a widening multiply
      accumulate in this mode/signedness combination, otherwise
      this transformation is likely to pessimize code.  */