OSDN Git Service

2010-04-28 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-ifcombine.c
index 143608e..8b8e0dd 100644 (file)
@@ -1,5 +1,5 @@
 /* Combining of if-expressions on trees.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
    Contributed by Richard Guenther <rguenther@suse.de>
 
 This file is part of GCC.
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "basic-block.h"
 #include "timevar.h"
 #include "diagnostic.h"
+#include "tree-pretty-print.h"
 #include "tree-flow.h"
 #include "tree-pass.h"
 #include "tree-dump.h"
@@ -108,7 +109,7 @@ bb_no_side_effects_p (basic_block bb)
       gimple stmt = gsi_stmt (gsi);
 
       if (gimple_has_volatile_ops (stmt)
-         || !ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
+         || gimple_vuse (stmt))
        return false;
     }
 
@@ -151,7 +152,7 @@ get_name_for_bit_test (tree candidate)
     {
       gimple def_stmt = SSA_NAME_DEF_STMT (candidate);
       if (is_gimple_assign (def_stmt)
-         && gimple_assign_cast_p (def_stmt))
+         && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)))
        {
          if (TYPE_PRECISION (TREE_TYPE (candidate))
              <= TYPE_PRECISION (TREE_TYPE (gimple_assign_rhs1 (def_stmt))))
@@ -162,21 +163,6 @@ get_name_for_bit_test (tree candidate)
   return candidate;
 }
 
-/* Helpers for recognize_single_bit_test defined mainly for source code
-   formating.  */
-
-static int
-operand_precision (tree t)
-{
-  return TYPE_PRECISION (TREE_TYPE (t));
-}
-
-static bool
-integral_operand_p (tree t)
-{
-  return INTEGRAL_TYPE_P (TREE_TYPE (t));
-}
-
 /* Recognize a single bit test pattern in GIMPLE_COND and its defining
    statements.  Store the name being tested in *NAME and the bit
    in *BIT.  The GIMPLE_COND computes *NAME & (1 << *BIT).
@@ -212,15 +198,11 @@ recognize_single_bit_test (gimple cond, tree *name, tree *bit)
       stmt = SSA_NAME_DEF_STMT (orig_name);
 
       while (is_gimple_assign (stmt)
-            && (gimple_assign_copy_p (stmt)
-                || (gimple_assign_cast_p (stmt)
-                    && integral_operand_p (gimple_assign_lhs (stmt))
-                    && integral_operand_p (gimple_assign_rhs1 (stmt))
-                    && (operand_precision (gimple_assign_lhs (stmt))
-                        <= operand_precision (gimple_assign_rhs1 (stmt))))))
-       {
-         stmt = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
-       }
+            && ((CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))
+                 && (TYPE_PRECISION (TREE_TYPE (gimple_assign_lhs (stmt)))
+                     <= TYPE_PRECISION (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
+                || gimple_assign_ssa_name_copy_p (stmt)))
+       stmt = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
 
       /* If we found such, decompose it.  */
       if (is_gimple_assign (stmt)
@@ -359,6 +341,9 @@ ifcombine_ifandif (basic_block inner_cond_bb, basic_block outer_cond_bb)
       t2 = force_gimple_operand_gsi (&gsi, t2, true, NULL_TREE,
                                     true, GSI_SAME_STMT);
       t = fold_build2 (EQ_EXPR, boolean_type_node, t2, t);
+      t = canonicalize_cond_expr_cond (t);
+      if (!t)
+       return false;
       gimple_cond_set_condition_from_tree (inner_cond, t);
       update_stmt (inner_cond);
 
@@ -380,6 +365,44 @@ ifcombine_ifandif (basic_block inner_cond_bb, basic_block outer_cond_bb)
       return true;
     }
 
+  /* See if we have two comparisons that we can merge into one.  */
+  else if (TREE_CODE_CLASS (gimple_cond_code (inner_cond)) == tcc_comparison
+          && TREE_CODE_CLASS (gimple_cond_code (outer_cond)) == tcc_comparison
+          && operand_equal_p (gimple_cond_lhs (inner_cond),
+                              gimple_cond_lhs (outer_cond), 0)
+          && operand_equal_p (gimple_cond_rhs (inner_cond),
+                              gimple_cond_rhs (outer_cond), 0))
+    {
+      enum tree_code code1 = gimple_cond_code (inner_cond);
+      enum tree_code code2 = gimple_cond_code (outer_cond);
+      tree t;
+
+      if (!(t = combine_comparisons (UNKNOWN_LOCATION,
+                                    TRUTH_ANDIF_EXPR, code1, code2,
+                                    boolean_type_node,
+                                    gimple_cond_lhs (outer_cond),
+                                    gimple_cond_rhs (outer_cond))))
+       return false;
+      t = canonicalize_cond_expr_cond (t);
+      if (!t)
+       return false;
+      gimple_cond_set_condition_from_tree (inner_cond, t);
+      update_stmt (inner_cond);
+
+      /* Leave CFG optimization to cfg_cleanup.  */
+      gimple_cond_set_condition_from_tree (outer_cond, boolean_true_node);
+      update_stmt (outer_cond);
+
+      if (dump_file)
+       {
+         fprintf (dump_file, "optimizing two comparisons to ");
+         print_generic_expr (dump_file, t, 0);
+         fprintf (dump_file, "\n");
+       }
+
+      return true;
+    }
+
   return false;
 }
 
@@ -440,6 +463,25 @@ ifcombine_iforif (basic_block inner_cond_bb, basic_block outer_cond_bb)
       else
        return false;
 
+      /* As we strip non-widening conversions in finding a common
+         name that is tested make sure to end up with an integral
+        type for building the bit operations.  */
+      if (TYPE_PRECISION (TREE_TYPE (bits1))
+         >= TYPE_PRECISION (TREE_TYPE (bits2)))
+       {
+         bits1 = fold_convert (unsigned_type_for (TREE_TYPE (bits1)), bits1);
+         name1 = fold_convert (TREE_TYPE (bits1), name1);
+         bits2 = fold_convert (unsigned_type_for (TREE_TYPE (bits2)), bits2);
+         bits2 = fold_convert (TREE_TYPE (bits1), bits2);
+       }
+      else
+       {
+         bits2 = fold_convert (unsigned_type_for (TREE_TYPE (bits2)), bits2);
+         name1 = fold_convert (TREE_TYPE (bits2), name1);
+         bits1 = fold_convert (unsigned_type_for (TREE_TYPE (bits1)), bits1);
+         bits1 = fold_convert (TREE_TYPE (bits2), bits1);
+       }
+
       /* Do it.  */
       gsi = gsi_for_stmt (inner_cond);
       t = fold_build2 (BIT_IOR_EXPR, TREE_TYPE (name1), bits1, bits2);
@@ -450,6 +492,9 @@ ifcombine_iforif (basic_block inner_cond_bb, basic_block outer_cond_bb)
                                    true, GSI_SAME_STMT);
       t = fold_build2 (NE_EXPR, boolean_type_node, t,
                       build_int_cst (TREE_TYPE (t), 0));
+      t = canonicalize_cond_expr_cond (t);
+      if (!t)
+       return false;
       gimple_cond_set_condition_from_tree (inner_cond, t);
       update_stmt (inner_cond);
 
@@ -483,42 +528,14 @@ ifcombine_iforif (basic_block inner_cond_bb, basic_block outer_cond_bb)
     {
       enum tree_code code1 = gimple_cond_code (inner_cond);
       enum tree_code code2 = gimple_cond_code (outer_cond);
-      enum tree_code code;
       tree t;
 
-#define CHK(a,b) ((code1 == a ## _EXPR && code2 == b ## _EXPR) \
-                 || (code2 == a ## _EXPR && code1 == b ## _EXPR))
-      /* Merge the two condition codes if possible.  */
-      if (code1 == code2)
-       code = code1;
-      else if (CHK (EQ, LT))
-       code = LE_EXPR;
-      else if (CHK (EQ, GT))
-       code = GE_EXPR;
-      else if (CHK (LT, LE))
-       code = LE_EXPR;
-      else if (CHK (GT, GE))
-       code = GE_EXPR;
-      else if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (inner_cond)))
-              || flag_unsafe_math_optimizations)
-       {
-         if (CHK (LT, GT))
-           code = NE_EXPR;
-         else if (CHK (LT, NE))
-           code = NE_EXPR;
-         else if (CHK (GT, NE))
-           code = NE_EXPR;
-         else
-           return false;
-       }
-      /* We could check for combinations leading to trivial true/false.  */
-      else
+      if (!(t = combine_comparisons (UNKNOWN_LOCATION,
+                                    TRUTH_ORIF_EXPR, code1, code2,
+                                    boolean_type_node,
+                                    gimple_cond_lhs (outer_cond),
+                                    gimple_cond_rhs (outer_cond))))
        return false;
-#undef CHK
-
-      /* Do it.  */
-      t = fold_build2 (code, boolean_type_node, gimple_cond_lhs (outer_cond),
-                      gimple_cond_rhs (outer_cond));
       t = canonicalize_cond_expr_cond (t);
       if (!t)
        return false;
@@ -641,7 +658,7 @@ gate_ifcombine (void)
   return 1;
 }
 
-struct gimple_opt_pass pass_tree_ifcombine = 
+struct gimple_opt_pass pass_tree_ifcombine =
 {
  {
   GIMPLE_PASS,