tree-switch-conversion.c (struct switch_conv_info): Add range_max, reorganize some...
authorSteven Bosscher <steven@gcc.gnu.org>
Fri, 27 Apr 2012 11:11:45 +0000 (11:11 +0000)
committerSteven Bosscher <steven@gcc.gnu.org>
Fri, 27 Apr 2012 11:11:45 +0000 (11:11 +0000)
gcc/
* tree-switch-conversion.c (struct switch_conv_info): Add range_max,
reorganize some fields and update comments.  Rename bit_test_uniq
and bit_test_count to uniq resp. count.  Remove bit_test_bb.
(collect_switch_conv_info): New function, collects info about a
GIMPLE_SWITCH into a struct switch_conv_info.
(check_range): Simplify to use pre-recorded info.  Fix think-o in
range-branch ratio check.
(check_process_case): Remove function.
(check_all_empty_except_final): New function, verifies that all
non-final basic blocks are empty.
(process_switch): Simplify to use pre-recorded info.  Call
collect_switch_conv_info to do that.  Assert that degenerate switch
statements have been cleaned up.

From-SVN: r186901

gcc/ChangeLog
gcc/tree-switch-conversion.c

index 76578cb6d4c640b8e26bc58c6f3a21619bb8c9b9..f4c19ea566bee68333ad50dd3e30f3b3ffcc2e91 100644 (file)
@@ -1,3 +1,19 @@
+2012-04-27  Steven Bosscher  <steven@gcc.gnu.org>
+
+       * tree-switch-conversion.c (struct switch_conv_info): Add range_max,
+       reorganize some fields and update comments.  Rename bit_test_uniq
+       and bit_test_count to uniq resp. count.  Remove bit_test_bb.
+       (collect_switch_conv_info): New function, collects info about a
+       GIMPLE_SWITCH into a struct switch_conv_info.
+       (check_range): Simplify to use pre-recorded info.  Fix think-o in
+       range-branch ratio check.
+       (check_process_case): Remove function.
+       (check_all_empty_except_final): New function, verifies that all
+       non-final basic blocks are empty.
+       (process_switch): Simplify to use pre-recorded info.  Call
+       collect_switch_conv_info to do that.  Assert that degenerate switch
+       statements have been cleaned up.
+
 2012-04-27  Marc Glisse  <marc.glisse@inria.fr>
 
        PR middle-end/27139
index 95c8bd805e12f04df6b56ecf1b5113c5da74e87b..3d10750e4dc480996f0bc2322fbd7d2be7a83d2d 100644 (file)
@@ -48,6 +48,7 @@ provided.  For example, the following code:
          default:
                 a_4 = 16;
                 b_4 = 1;
+               break;
         }
        a_5 = PHI <a_1, a_2, a_3, a_4>
        b_5 = PHI <b_1, b_2, b_3, b_4>
@@ -69,8 +70,8 @@ is changed into:
            a_7 = 16;
            b_7 = 1;
           }
-         a_5 = PHI <a_6, a_7>
-         b_b = PHI <b_6, b_7>
+       a_5 = PHI <a_6, a_7>
+       b_b = PHI <b_6, b_7>
 
 There are further constraints.  Specifically, the range of values across all
 case labels must not be bigger than SWITCH_CONVERSION_BRANCH_RATIO (default
@@ -99,25 +100,38 @@ eight) times the number of the actual switch branches. */
 /* The main structure of the pass.  */
 struct switch_conv_info
 {
-  /* The expression used to decide the switch branch.  (It is subsequently used
-     as the index to the created array.) */
+  /* The expression used to decide the switch branch.  */
   tree index_expr;
 
-  /* The following integer constants store the minimum value covered by the
-     cases.  */
+  /* The following integer constants store the minimum and maximum value
+     covered by the case labels.  */
   tree range_min;
+  tree range_max;
 
-  /* The difference between the above two numbers, i.e. The size of the array
-     that would have to be created by the transformation.  */
+  /* The difference between the above two numbers.  Stored here because it
+     is used in all the conversion heuristics, as well as for some of the
+     transformation, and it is expensive to re-compute it all the time.  */
   tree range_size;
 
-  /* Basic block that contains the actual SWITCH_EXPR.  */
+  /* Basic block that contains the actual GIMPLE_SWITCH.  */
   basic_block switch_bb;
 
-  /* All branches of the switch statement must have a single successor stored in
-     the following variable.  */
+  /* Basic block that is the target of the default case.  */
+  basic_block default_bb;
+
+  /* The single successor block of all branches out of the GIMPLE_SWITCH,
+     if such a block exists.  Otherwise NULL.  */
   basic_block final_bb;
 
+  /* The probability of the default edge in the replaced switch.  */
+  int default_prob;
+
+  /* The count of the default edge in the replaced switch.  */
+  gcov_type default_count;
+
+  /* Combined count of all other (non-default) edges in the replaced switch.  */
+  gcov_type other_count;
+
   /* Number of phi nodes in the final bb (that we'll be replacing).  */
   int phi_count;
 
@@ -135,15 +149,6 @@ struct switch_conv_info
      switch expression is out of range.  */
   tree *target_outbound_names;
 
-  /* The probability of the default edge in the replaced switch.  */
-  int default_prob;
-
-  /* The count of the default edge in the replaced switch.  */
-  gcov_type default_count;
-
-  /* Combined count of all other (non-default) edges in the replaced switch.  */
-  gcov_type other_count;
-
   /* The first load statement that loads a temporary from a new static array.
    */
   gimple arr_ref_first;
@@ -157,41 +162,104 @@ struct switch_conv_info
 
   /* Parameters for expand_switch_using_bit_tests.  Should be computed
      the same way as in expand_case.  */
-  unsigned int bit_test_uniq;
-  unsigned int bit_test_count;
-  basic_block bit_test_bb[2];
+  unsigned int uniq;
+  unsigned int count;
 };
 
-/* Checks whether the range given by individual case statements of the SWTCH
-   switch statement isn't too big and whether the number of branches actually
-   satisfies the size of the new array.  */
+/* Collect information about GIMPLE_SWITCH statement SWTCH into INFO.  */
 
-static bool
-check_range (gimple swtch, struct switch_conv_info *info)
+static void
+collect_switch_conv_info (gimple swtch, struct switch_conv_info *info)
 {
-  tree min_case, max_case;
   unsigned int branch_num = gimple_switch_num_labels (swtch);
-  tree range_max;
+  tree min_case, max_case;
+  unsigned int count, i;
+  edge e, e_default;
+  edge_iterator ei;
+
+  memset (info, 0, sizeof (*info));
 
   /* The gimplifier has already sorted the cases by CASE_LOW and ensured there
      is a default label which is the first in the vector.  */
+  gcc_assert (CASE_LOW (gimple_switch_label (swtch, 0)) == NULL_TREE);
 
-  min_case = gimple_switch_label (swtch, 1);
-  info->range_min = CASE_LOW (min_case);
+  /* Collect the bits we can deduce from the CFG.  */
+  info->index_expr = gimple_switch_index (swtch);
+  info->switch_bb = gimple_bb (swtch);
+  info->default_bb =
+    label_to_block (CASE_LABEL (gimple_switch_label (swtch, 0)));
+  e_default = find_edge (info->switch_bb, info->default_bb);
+  info->default_prob = e_default->probability;
+  info->default_count = e_default->count;
+  FOR_EACH_EDGE (e, ei, info->switch_bb->succs)
+    if (e != e_default)
+      info->other_count += e->count;
 
-  gcc_assert (branch_num > 1);
-  gcc_assert (CASE_LOW (gimple_switch_label (swtch, 0)) == NULL_TREE);
+  /* See if there is one common successor block for all branch
+     targets.  If it exists, record it in FINAL_BB.  */
+  FOR_EACH_EDGE (e, ei, info->switch_bb->succs)
+    {
+      if (! single_pred_p (e->dest))
+       {
+         info->final_bb = e->dest;
+         break;
+       }
+    }
+  if (info->final_bb)
+    FOR_EACH_EDGE (e, ei, info->switch_bb->succs)
+      {
+       if (e->dest == info->final_bb)
+         continue;
+
+       if (single_pred_p (e->dest)
+           && single_succ_p (e->dest)
+           && single_succ (e->dest) == info->final_bb)
+         continue;
+
+       info->final_bb = NULL;
+       break;
+      }
+
+  /* Get upper and lower bounds of case values, and the covered range.  */
+  min_case = gimple_switch_label (swtch, 1);
   max_case = gimple_switch_label (swtch, branch_num - 1);
+
+  info->range_min = CASE_LOW (min_case);
   if (CASE_HIGH (max_case) != NULL_TREE)
-    range_max = CASE_HIGH (max_case);
+    info->range_max = CASE_HIGH (max_case);
   else
-    range_max = CASE_LOW (max_case);
+    info->range_max = CASE_LOW (max_case);
 
-  gcc_assert (info->range_min);
-  gcc_assert (range_max);
+  info->range_size =
+    int_const_binop (MINUS_EXPR, info->range_max, info->range_min);
 
-  info->range_size = int_const_binop (MINUS_EXPR, range_max, info->range_min);
+  /* Get a count of the number of case labels.  Single-valued case labels
+     simply count as one, but a case range counts double, since it may
+     require two compares if it gets lowered as a branching tree.  */
+  count = 0;
+  for (i = 1; i < branch_num; i++)
+    {
+      tree elt = gimple_switch_label (swtch, i);
+      count++;
+      if (CASE_HIGH (elt)
+         && ! tree_int_cst_equal (CASE_LOW (elt), CASE_HIGH (elt)))
+       count++;
+    }
+  info->count = count;
+  /* Get the number of unique non-default targets out of the GIMPLE_SWITCH
+     block.  Assume a CFG cleanup would have already removed degenerate
+     switch statements, this allows us to just use EDGE_COUNT.  */
+  info->uniq = EDGE_COUNT (gimple_bb (swtch)->succs) - 1;
+}
 
+/* Checks whether the range given by individual case statements of the SWTCH
+   switch statement isn't too big and whether the number of branches actually
+   satisfies the size of the new array.  */
+
+static bool
+check_range (struct switch_conv_info *info)
+{
   gcc_assert (info->range_size);
   if (!host_integerp (info->range_size, 1))
     {
@@ -200,7 +268,7 @@ check_range (gimple swtch, struct switch_conv_info *info)
     }
 
   if ((unsigned HOST_WIDE_INT) tree_low_cst (info->range_size, 1)
-      > ((unsigned) branch_num * SWITCH_CONVERSION_BRANCH_RATIO))
+      > ((unsigned) info->count * SWITCH_CONVERSION_BRANCH_RATIO))
     {
       info->reason = "the maximum range-branch ratio exceeded";
       return false;
@@ -209,86 +277,24 @@ check_range (gimple swtch, struct switch_conv_info *info)
   return true;
 }
 
-/* Checks the given CS switch case whether it is suitable for conversion
-   (whether all but the default basic blocks are empty and so on).  If it is,
-   adds the case to the branch list along with values for the defined variables
-   and returns true.  Otherwise returns false.  */
+/* Checks whether all but the FINAL_BB basic blocks are empty.  */
 
 static bool
-check_process_case (tree cs, struct switch_conv_info *info)
+check_all_empty_except_final (struct switch_conv_info *info)
 {
-  tree ldecl;
-  basic_block label_bb, following_bb;
   edge e;
+  edge_iterator ei;
 
-  ldecl = CASE_LABEL (cs);
-  label_bb = label_to_block (ldecl);
-
-  e = find_edge (info->switch_bb, label_bb);
-  gcc_assert (e);
-
-  if (CASE_LOW (cs) == NULL_TREE)
-    {
-      /* Default branch.  */
-      info->default_prob = e->probability;
-      info->default_count = e->count;
-    }
-  else
-    {
-      int i;
-      info->other_count += e->count;
-      for (i = 0; i < 2; i++)
-       if (info->bit_test_bb[i] == label_bb)
-         break;
-       else if (info->bit_test_bb[i] == NULL)
-         {
-           info->bit_test_bb[i] = label_bb;
-           info->bit_test_uniq++;
-           break;
-         }
-      if (i == 2)
-       info->bit_test_uniq = 3;
-      if (CASE_HIGH (cs) != NULL_TREE
-         && ! tree_int_cst_equal (CASE_LOW (cs), CASE_HIGH (cs)))
-       info->bit_test_count += 2;
-      else
-       info->bit_test_count++;
-    }
-
-  if (!label_bb)
-    {
-      info->reason = "bad case - cs BB  label is NULL";
-      return false;
-    }
-
-  if (!single_pred_p (label_bb))
+  FOR_EACH_EDGE (e, ei, info->switch_bb->succs)
     {
-      if (info->final_bb && info->final_bb != label_bb)
-       {
-         info->reason = "bad case - a non-final BB has two predecessors";
-         return false; /* sth complex going on in this branch  */
-       }
+      if (e->dest == info->final_bb)
+       continue;
 
-      following_bb = label_bb;
-    }
-  else
-    {
-      if (!empty_block_p (label_bb))
+      if (!empty_block_p (e->dest))
        {
          info->reason = "bad case - a non-final BB not empty";
          return false;
        }
-
-      e = single_succ_edge (label_bb);
-      following_bb = single_succ (label_bb);
-    }
-
-  if (!info->final_bb)
-    info->final_bb = following_bb;
-  else if (info->final_bb != following_bb)
-    {
-      info->reason = "bad case - different final BB";
-      return false; /* the only successor is not common for all the branches */
     }
 
   return true;
@@ -878,36 +884,30 @@ gen_inbound_check (gimple swtch, struct switch_conv_info *info)
 static const char *
 process_switch (gimple swtch)
 {
-  unsigned int i, branch_num = gimple_switch_num_labels (swtch);
-  tree index_type;
   struct switch_conv_info info;
 
-  /* Operand 2 is either NULL_TREE or a vector of cases (stmt.c).  */
-  if (branch_num < 2)
-    return "switch has no labels";
-
-  info.reason = NULL;
-  info.final_bb = NULL;
-  info.switch_bb = gimple_bb (swtch);
-  info.index_expr = gimple_switch_index (swtch);
-  info.arr_ref_first = NULL;
-  info.arr_ref_last = NULL;
-  info.default_prob = 0;
-  info.default_count = 0;
-  info.other_count = 0;
-  info.bit_test_uniq = 0;
-  info.bit_test_count = 0;
-  info.bit_test_bb[0] = NULL;
-  info.bit_test_bb[1] = NULL;
-
-  /* An ERROR_MARK occurs for various reasons including invalid data type.
-     (comment from stmt.c) */
-  index_type = TREE_TYPE (info.index_expr);
-  if (index_type == error_mark_node)
-    return "index error\n";
+  /* Degenerate case with only a default label should never happen.  */
+  gcc_checking_assert (gimple_switch_num_labels (swtch) > 1);
+
+  collect_switch_conv_info (swtch, &info);
+
+  /* No error markers should reach here (they should be filtered out
+     during gimplification).  */
+  gcc_checking_assert (TREE_TYPE (info.index_expr) != error_mark_node);
+
+  /* If there is no common successor, we cannot do the transformation.  */
+  if (! info.final_bb)
+    return "no common successor to all case label target blocks found";
+
+  if (info.uniq <= 2)
+    {
+      if (expand_switch_using_bit_tests_p (info.index_expr, info.range_size,
+                                          info.uniq, info.count))
+       return "expanding as bit test is preferable";
+    }
 
   /* Check the case label values are within reasonable range:  */
-  if (!check_range (swtch, &info))
+  if (!check_range (&info))
     {
       gcc_assert (info.reason);
       return info.reason;
@@ -915,26 +915,11 @@ process_switch (gimple swtch)
 
   /* For all the cases, see whether they are empty, the assignments they
      represent constant and so on...  */
-  for (i = 0; i < branch_num; i++)
-    if (!check_process_case (gimple_switch_label (swtch, i), &info))
-      {
-       gcc_assert (info.reason);
-       if (dump_file)
-         fprintf (dump_file, "processing of case %i failed\n\t", i);
-       return info.reason;
-      }
-
-  if (info.bit_test_uniq <= 2)
+  if (! check_all_empty_except_final (&info))
     {
-      rtl_profile_for_bb (gimple_bb (swtch));
-      if (expand_switch_using_bit_tests_p (gimple_switch_index (swtch),
-                                          info.range_size, info.bit_test_uniq,
-                                          info.bit_test_count))
-       {
-         return "expanding as bit test is preferable";
-       }
+      gcc_assert (info.reason);
+      return info.reason;
     }
-
   if (!check_final_bb (&info))
     {
       gcc_assert (info.reason);