tree-ssa-forwprop.c (combine_conversions): Pattern-match a series of conversions...
authorRichard Guenther <rguenther@suse.de>
Tue, 10 May 2011 09:57:50 +0000 (09:57 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Tue, 10 May 2011 09:57:50 +0000 (09:57 +0000)
2011-05-10  Richard Guenther  <rguenther@suse.de>

* tree-ssa-forwprop.c (combine_conversions): Pattern-match
a series of conversions and apply foldings similar to what
fold-const does.
(tree_ssa_forward_propagate_single_use_vars): Call it.

* gcc.dg/tree-ssa/ssa-fre-2.c: Disable forwprop.
* gcc.dg/tree-ssa/ssa-fre-3.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-4.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-5.c: Likewise.
* gcc.dg/tree-ssa/scev-cast.c: Adjust.  Note what transformation
applies.

From-SVN: r173612

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/scev-cast.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-2.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-3.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-4.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-5.c
gcc/tree-ssa-forwprop.c

index b98c123176009cb4b76bc31ef5259888fbd144be..7e5d7b957d3421223ce406ad58aca6413d01ef55 100644 (file)
@@ -1,3 +1,10 @@
+2011-05-10  Richard Guenther  <rguenther@suse.de>
+
+       * tree-ssa-forwprop.c (combine_conversions): Pattern-match
+       a series of conversions and apply foldings similar to what
+       fold-const does.
+       (tree_ssa_forward_propagate_single_use_vars): Call it.
+
 2011-05-10  Jakub Jelinek  <jakub@redhat.com>
 
        PR tree-optimization/48611
index c63b45e58b54649cd82e049ddf85dce219a5d3fc..f57c040561ece0eec64edd72ba62159c2a3267b0 100644 (file)
@@ -1,3 +1,12 @@
+2011-05-10  Richard Guenther  <rguenther@suse.de>
+
+       * gcc.dg/tree-ssa/ssa-fre-2.c: Disable forwprop.
+       * gcc.dg/tree-ssa/ssa-fre-3.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-fre-4.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-fre-5.c: Likewise.
+       * gcc.dg/tree-ssa/scev-cast.c: Adjust.  Note what transformation
+       applies.
+
 2011-05-10  Jakub Jelinek  <jakub@redhat.com>
 
        PR tree-optimization/48611
index 2cf245460ee1fc601e97be981d63e2acb6bcd56c..8120dad7fe9d5081f54fd2038217ec5508a6de67 100644 (file)
@@ -3,24 +3,26 @@
 /* { dg-do compile { target i?86-*-* x86_64-*-* } } */
 /* { dg-options "-O2 -fdump-tree-optimized" } */
 
-void blas (char xxx);
+void blas (signed char xxx);
 void blau (unsigned char xxx);
 
 void tst(void)
 {
   unsigned i;
 
-  for (i = 0; i < 128; i++) /* This cast to char has to be preserved.  */
-    blas ((char) i);
-  for (i = 0; i < 127; i++) /* And this one does not.  */
-    blas ((char) i);
-  for (i = 0; i < 255; i++) /* This cast is not necessary.  */
+  for (i = 0; i < 129; i++) /* This truncation to char has to be preserved.  */
+    blas ((signed char) i);
+  for (i = 0; i < 128; i++) /* This one is not necessary, but nothing eliminates it.  */
+    blas ((signed char) i);
+  for (i = 0; i < 127; i++) /* This one is not necessary, IVOPTS eliminates it.  */
+    blas ((signed char) i);
+  for (i = 0; i < 256; i++) /* This one is not necessary, VRP eliminates it.  */
+    blau ((unsigned char) i);
+  for (i = 0; i < 257; i++) /* This one is necessary.  */
     blau ((unsigned char) i);
-  for (i = 0; i < 256; i++)
-    blau ((unsigned char) i); /* This one is necessary.  */
 }
 
-/* { dg-final { scan-tree-dump-times "= \\(unsigned char\\)" 1 "optimized" } } */
-/* { dg-final { scan-tree-dump-times "= \\(char\\)" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "& 255" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "= \\(signed char\\)" 2 "optimized" } } */
 
 /* { dg-final { cleanup-tree-dump "optimized" } } */
index 9bf9525d50251dcf0add5ae53920fec4ebf0fad7..f85c06139f21712db07338665581eb70b0eacb1c 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-fre1-details" } */
+/* { dg-options "-O -fno-tree-forwprop -fdump-tree-fre1-details" } */
 
 /* From PR14287.  */
 
index e68c9eb7bc43f92e01cbb47e2d0927e9e6390612..6813b4323020bc710f7550a10ba3679fbd4b5fa7 100644 (file)
@@ -6,7 +6,7 @@
    When the condition is true, we distribute "(int) (a + b)" as
    "(int) a + (int) b", otherwise we keep the original.  */
 /* { dg-do compile { target { { ! mips64 } && { ! spu-*-* } } } } */
-/* { dg-options "-O -fwrapv -fdump-tree-fre1-details" } */
+/* { dg-options "-O -fno-tree-forwprop -fwrapv -fdump-tree-fre1-details" } */
 
 /* From PR14844.  */
 
index b69b3f654d1fb77f53ce10b4f99b39ddeb5b04e2..96738305bbcf02ce038a164d02cbd1c1908184a7 100644 (file)
@@ -1,7 +1,7 @@
 /* If the target returns false for TARGET_PROMOTE_PROTOTYPES, then there
    will be no casts for FRE to eliminate and the test will fail.  */
 /* { dg-do compile { target i?86-*-* x86_64-*-* hppa*-*-* mips*-*-* m68k*-*-* } } */
-/* { dg-options "-O -fdump-tree-fre1-details" } */
+/* { dg-options "-O -fno-tree-forwprop -fdump-tree-fre1-details" } */
 
 /* From PR21608.  */
 
index 2685d91b12e68d021430c33797373877c7cd8b5b..e6010ca031835202ec815f9eb10ef114aed3b36e 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-fre1-details" } */
+/* { dg-options "-O -fno-tree-forwprop -fdump-tree-fre1-details" } */
 
 /* From PR19792.  */
 
index 7990c5b55983f49a2c2fd7613b1aaf89145208cd..65e058d7231a3c7df6771ed7c427076bb57531f7 100644 (file)
@@ -1938,6 +1938,166 @@ out:
   return false;
 }
 
+/* Combine two conversions in a row for the second conversion at *GSI.
+   Returns true if there were any changes made.  */
+static bool
+combine_conversions (gimple_stmt_iterator *gsi)
+{
+  gimple stmt = gsi_stmt (*gsi);
+  gimple def_stmt;
+  tree op0, lhs;
+  enum tree_code code = gimple_assign_rhs_code (stmt);
+
+  gcc_checking_assert (CONVERT_EXPR_CODE_P (code)
+                      || code == FLOAT_EXPR
+                      || code == FIX_TRUNC_EXPR);
+
+  lhs = gimple_assign_lhs (stmt);
+  op0 = gimple_assign_rhs1 (stmt);
+  if (useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (op0)))
+    {
+      gimple_assign_set_rhs_code (stmt, TREE_CODE (op0));
+      return true;
+    }
+
+  if (TREE_CODE (op0) != SSA_NAME)
+    return false;
+
+  def_stmt = SSA_NAME_DEF_STMT (op0);
+  if (!is_gimple_assign (def_stmt))
+    return false;
+
+  if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)))
+    {
+      tree defop0 = gimple_assign_rhs1 (def_stmt);
+      tree type = TREE_TYPE (lhs);
+      tree inside_type = TREE_TYPE (defop0);
+      tree inter_type = TREE_TYPE (op0);
+      int inside_int = INTEGRAL_TYPE_P (inside_type);
+      int inside_ptr = POINTER_TYPE_P (inside_type);
+      int inside_float = FLOAT_TYPE_P (inside_type);
+      int inside_vec = TREE_CODE (inside_type) == VECTOR_TYPE;
+      unsigned int inside_prec = TYPE_PRECISION (inside_type);
+      int inside_unsignedp = TYPE_UNSIGNED (inside_type);
+      int inter_int = INTEGRAL_TYPE_P (inter_type);
+      int inter_ptr = POINTER_TYPE_P (inter_type);
+      int inter_float = FLOAT_TYPE_P (inter_type);
+      int inter_vec = TREE_CODE (inter_type) == VECTOR_TYPE;
+      unsigned int inter_prec = TYPE_PRECISION (inter_type);
+      int inter_unsignedp = TYPE_UNSIGNED (inter_type);
+      int final_int = INTEGRAL_TYPE_P (type);
+      int final_ptr = POINTER_TYPE_P (type);
+      int final_float = FLOAT_TYPE_P (type);
+      int final_vec = TREE_CODE (type) == VECTOR_TYPE;
+      unsigned int final_prec = TYPE_PRECISION (type);
+      int final_unsignedp = TYPE_UNSIGNED (type);
+
+      /* In addition to the cases of two conversions in a row
+        handled below, if we are converting something to its own
+        type via an object of identical or wider precision, neither
+        conversion is needed.  */
+      if (useless_type_conversion_p (type, inside_type)
+         && (((inter_int || inter_ptr) && final_int)
+             || (inter_float && final_float))
+         && inter_prec >= final_prec)
+       {
+         gimple_assign_set_rhs1 (stmt, unshare_expr (defop0));
+         gimple_assign_set_rhs_code (stmt, TREE_CODE (defop0));
+         update_stmt (stmt);
+         return true;
+       }
+
+      /* Likewise, if the intermediate and initial types are either both
+        float or both integer, we don't need the middle conversion if the
+        former is wider than the latter and doesn't change the signedness
+        (for integers).  Avoid this if the final type is a pointer since
+        then we sometimes need the middle conversion.  Likewise if the
+        final type has a precision not equal to the size of its mode.  */
+      if (((inter_int && inside_int)
+          || (inter_float && inside_float)
+          || (inter_vec && inside_vec))
+         && inter_prec >= inside_prec
+         && (inter_float || inter_vec
+             || inter_unsignedp == inside_unsignedp)
+         && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
+               && TYPE_MODE (type) == TYPE_MODE (inter_type))
+         && ! final_ptr
+         && (! final_vec || inter_prec == inside_prec))
+       {
+         gimple_assign_set_rhs1 (stmt, defop0);
+         update_stmt (stmt);
+         return true;
+       }
+
+      /* If we have a sign-extension of a zero-extended value, we can
+        replace that by a single zero-extension.  */
+      if (inside_int && inter_int && final_int
+         && inside_prec < inter_prec && inter_prec < final_prec
+         && inside_unsignedp && !inter_unsignedp)
+       {
+         gimple_assign_set_rhs1 (stmt, defop0);
+         update_stmt (stmt);
+         return true;
+       }
+
+      /* Two conversions in a row are not needed unless:
+        - some conversion is floating-point (overstrict for now), or
+        - some conversion is a vector (overstrict for now), or
+        - the intermediate type is narrower than both initial and
+        final, or
+        - the intermediate type and innermost type differ in signedness,
+        and the outermost type is wider than the intermediate, or
+        - the initial type is a pointer type and the precisions of the
+        intermediate and final types differ, or
+        - the final type is a pointer type and the precisions of the
+        initial and intermediate types differ.  */
+      if (! inside_float && ! inter_float && ! final_float
+         && ! inside_vec && ! inter_vec && ! final_vec
+         && (inter_prec >= inside_prec || inter_prec >= final_prec)
+         && ! (inside_int && inter_int
+               && inter_unsignedp != inside_unsignedp
+               && inter_prec < final_prec)
+         && ((inter_unsignedp && inter_prec > inside_prec)
+             == (final_unsignedp && final_prec > inter_prec))
+         && ! (inside_ptr && inter_prec != final_prec)
+         && ! (final_ptr && inside_prec != inter_prec)
+         && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
+               && TYPE_MODE (type) == TYPE_MODE (inter_type)))
+       {
+         gimple_assign_set_rhs1 (stmt, defop0);
+         update_stmt (stmt);
+         return true;
+       }
+
+      /* A truncation to an unsigned type should be canonicalized as
+        bitwise and of a mask.  */
+      if (final_int && inter_int && inside_int
+         && final_prec == inside_prec
+         && final_prec > inter_prec
+         && inter_unsignedp)
+       {
+         tree tem;
+         tem = fold_build2 (BIT_AND_EXPR, inside_type,
+                            defop0,
+                            double_int_to_tree
+                              (inside_type, double_int_mask (inter_prec)));
+         if (!useless_type_conversion_p (type, inside_type))
+           {
+             tem = force_gimple_operand_gsi (gsi, tem, true, NULL_TREE, true,
+                                             GSI_SAME_STMT);
+             gimple_assign_set_rhs1 (stmt, tem);
+           }
+         else
+           gimple_assign_set_rhs_from_tree (gsi, tem);
+         update_stmt (gsi_stmt (*gsi));
+         return true;
+       }
+    }
+
+  return false;
+}
+
 /* Main entry point for the forward propagation optimizer.  */
 
 static unsigned int
@@ -2061,6 +2221,13 @@ tree_ssa_forward_propagate_single_use_vars (void)
                  cfg_changed |= associate_plusminus (stmt);
                  gsi_next (&gsi);
                }
+             else if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))
+                      || gimple_assign_rhs_code (stmt) == FLOAT_EXPR
+                      || gimple_assign_rhs_code (stmt) == FIX_TRUNC_EXPR)
+               {
+                 if (!combine_conversions (&gsi))
+                   gsi_next (&gsi);
+               }
              else
                gsi_next (&gsi);
            }