OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / tree-switch-conversion.c
index 940801e..20888d2 100644 (file)
@@ -1,6 +1,6 @@
 /* Switch Conversion converts variable initializations based on switch
    statements to initializations from a static array.
-   Copyright (C) 2006, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
    Contributed by Martin Jambor <jamborm@suse.cz>
 
 This file is part of GCC.
@@ -80,8 +80,6 @@ eight) times the number of the actual switch branches. */
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include <signal.h>
-
 #include "line-map.h"
 #include "params.h"
 #include "flags.h"
@@ -93,8 +91,10 @@ eight) times the number of the actual switch branches. */
 #include "output.h"
 #include "input.h"
 #include "tree-pass.h"
-#include "diagnostic.h"
+#include "gimple-pretty-print.h"
 #include "tree-dump.h"
+#include "timevar.h"
+#include "langhooks.h"
 
 /* The main structure of the pass.  */
 struct switch_conv_info
@@ -107,7 +107,7 @@ struct switch_conv_info
      cases.  */
   tree range_min;
 
-  /* The difference of between the above two numbers, i.e. The size of the array
+  /* The difference between the above two numbers, i.e. The size of the array
      that would have to be created by the transformation.  */
   tree range_size;
 
@@ -121,7 +121,7 @@ struct switch_conv_info
   /* Number of phi nodes in the final bb (that we'll be replacing).  */
   int phi_count;
 
-  /* Array of default values, n the same order as phi nodes.  */
+  /* Array of default values, in the same order as phi nodes.  */
   tree *default_values;
 
   /* Constructors of new static arrays.  */
@@ -144,15 +144,22 @@ struct switch_conv_info
   /* Combined count of all other (non-default) edges in the replaced switch.  */
   gcov_type other_count;
 
-  /* The last load statement that loads a temporary from a new static array.  */
-  tree arr_ref_first;
+  /* The first load statement that loads a temporary from a new static array.
+   */
+  gimple arr_ref_first;
 
   /* The last load statement that loads a temporary from a new static array.  */
-  tree arr_ref_last;
+  gimple arr_ref_last;
 
   /* String reason why the case wasn't a good candidate that is written to the
      dump file, if there is one.  */
   const char *reason;
+
+  /* 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];
 };
 
 /* Global pass info.  */
@@ -164,22 +171,21 @@ static struct switch_conv_info info;
    satisfies the size of the new array.  */
 
 static bool
-check_range (tree swtch)
+check_range (gimple swtch)
 {
   tree min_case, max_case;
-  tree cases = SWITCH_LABELS (swtch);
-  unsigned int branch_num = TREE_VEC_LENGTH (cases);
+  unsigned int branch_num = gimple_switch_num_labels (swtch);
   tree range_max;
 
   /* The gimplifier has already sorted the cases by CASE_LOW and ensured there
-     is a default label which is the last in the vector.  */
+     is a default label which is the first in the vector.  */
 
-  min_case = TREE_VEC_ELT (cases, 0);
+  min_case = gimple_switch_label (swtch, 1);
   info.range_min = CASE_LOW (min_case);
 
   gcc_assert (branch_num > 1);
-  gcc_assert (CASE_LOW (TREE_VEC_ELT (cases, branch_num - 1)) == NULL_TREE);
-  max_case = TREE_VEC_ELT (cases, branch_num - 2);
+  gcc_assert (CASE_LOW (gimple_switch_label (swtch, 0)) == NULL_TREE);
+  max_case = gimple_switch_label (swtch, branch_num - 1);
   if (CASE_HIGH (max_case) != NULL_TREE)
     range_max = CASE_HIGH (max_case);
   else
@@ -188,7 +194,7 @@ check_range (tree swtch)
   gcc_assert (info.range_min);
   gcc_assert (range_max);
 
-  info.range_size = int_const_binop (MINUS_EXPR, range_max, info.range_min, 0);
+  info.range_size = int_const_binop (MINUS_EXPR, range_max, info.range_min);
 
   gcc_assert (info.range_size);
   if (!host_integerp (info.range_size, 1))
@@ -232,7 +238,26 @@ check_process_case (tree cs)
       info.default_count = e->count;
     }
   else
-    info.other_count += e->count;
+    {
+      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)
     {
@@ -258,7 +283,12 @@ check_process_case (tree cs)
          return false;
        }
 
-      e = single_succ_edge (label_bb);
+      if (!single_succ_p (label_bb))
+       {
+         info.reason
+           = "  Bad case - a non-final BB without a single successor\n";
+         return false;
+       }
       following_bb = single_succ (label_bb);
     }
 
@@ -281,25 +311,43 @@ check_process_case (tree cs)
 static bool
 check_final_bb (void)
 {
-  tree phi;
+  gimple_stmt_iterator gsi;
 
   info.phi_count = 0;
-  for (phi = phi_nodes (info.final_bb); phi; phi = PHI_CHAIN (phi))
+  for (gsi = gsi_start_phis (info.final_bb); !gsi_end_p (gsi); gsi_next (&gsi))
     {
-      int i;
+      gimple phi = gsi_stmt (gsi);
+      unsigned int i;
 
       info.phi_count++;
 
-      for (i = 0; i < PHI_NUM_ARGS (phi); i++)
+      for (i = 0; i < gimple_phi_num_args (phi); i++)
        {
-         basic_block bb = PHI_ARG_EDGE (phi, i)->src;
+         basic_block bb = gimple_phi_arg_edge (phi, i)->src;
 
-         if ((bb == info.switch_bb
-              || (single_pred_p (bb) && single_pred (bb) == info.switch_bb))
-             && !is_gimple_min_invariant (PHI_ARG_ELT (phi, i).def))
+         if (bb == info.switch_bb
+             || (single_pred_p (bb) && single_pred (bb) == info.switch_bb))
            {
-             info.reason = "   Non-invariant value from a case\n";
-             return false;             /* non invariant argument */
+             tree reloc, val;
+
+             val = gimple_phi_arg_def (phi, i);
+             if (!is_gimple_ip_invariant (val))
+               {
+                 info.reason = "   Non-invariant value from a case\n";
+                 return false; /* Non-invariant argument.  */
+               }
+             reloc = initializer_constant_valid_p (val, TREE_TYPE (val));
+             if ((flag_pic && reloc != null_pointer_node)
+                 || (!flag_pic && reloc == NULL_TREE))
+               {
+                 if (reloc)
+                   info.reason
+                     = "   Value from a case would need runtime relocations\n";
+                 else
+                   info.reason
+                     = "   Value from a case is not a valid initializer\n";
+                 return false;
+               }
            }
        }
     }
@@ -316,18 +364,13 @@ create_temp_arrays (void)
 {
   int i;
 
-  info.default_values = (tree *) xcalloc (info.phi_count, sizeof (tree));
-  info.constructors = (VEC (constructor_elt, gc) **) xcalloc (info.phi_count,
-                                                             sizeof (tree));
-  info.target_inbound_names = (tree *) xcalloc (info.phi_count, sizeof (tree));
-  info.target_outbound_names = (tree *) xcalloc (info.phi_count,
-                                                sizeof (tree));
-
+  info.default_values = XCNEWVEC (tree, info.phi_count * 3);
+  info.constructors = XCNEWVEC (VEC (constructor_elt, gc) *, info.phi_count);
+  info.target_inbound_names = info.default_values + info.phi_count;
+  info.target_outbound_names = info.target_inbound_names + info.phi_count;
   for (i = 0; i < info.phi_count; i++)
-    {
-      info.constructors[i] = VEC_alloc (constructor_elt, gc,
-                                  tree_low_cst (info.range_size, 1) + 1);
-    }
+    info.constructors[i]
+      = VEC_alloc (constructor_elt, gc, tree_low_cst (info.range_size, 1) + 1);
 }
 
 /* Free the arrays created by create_temp_arrays().  The vectors that are
@@ -337,10 +380,8 @@ create_temp_arrays (void)
 static void
 free_temp_arrays (void)
 {
-  free (info.constructors);
-  free (info.default_values);
-  free (info.target_inbound_names);
-  free (info.target_outbound_names);
+  XDELETEVEC (info.constructors);
+  XDELETEVEC (info.default_values);
 }
 
 /* Populate the array of default values in the order of phi nodes.
@@ -349,10 +390,10 @@ free_temp_arrays (void)
 static void
 gather_default_values (tree default_case)
 {
-  tree phi;
+  gimple_stmt_iterator gsi;
   basic_block bb = label_to_block (CASE_LABEL (default_case));
   edge e;
-  int i;
+  int i = 0;
 
   gcc_assert (CASE_LOW (default_case) == NULL_TREE);
 
@@ -361,11 +402,12 @@ gather_default_values (tree default_case)
   else
     e = single_succ_edge (bb);
 
-  for (phi = phi_nodes (info.final_bb), i = 0; phi; phi = PHI_CHAIN (phi), i++)
+  for (gsi = gsi_start_phis (info.final_bb); !gsi_end_p (gsi); gsi_next (&gsi))
     {
+      gimple phi = gsi_stmt (gsi);
       tree val = PHI_ARG_DEF_FROM_EDGE (phi, e);
       gcc_assert (val);
-      info.default_values[i] = val;
+      info.default_values[i++] = val;
     }
 }
 
@@ -374,18 +416,18 @@ gather_default_values (tree default_case)
    order of phi nodes.  SWTCH is the switch statement being converted.  */
 
 static void
-build_constructors (tree swtch)
+build_constructors (gimple swtch)
 {
-  int i;
-  tree cases = SWITCH_LABELS (swtch);
+  unsigned i, branch_num = gimple_switch_num_labels (swtch);
   tree pos = info.range_min;
 
-  for (i = 0; i < TREE_VEC_LENGTH (cases) - 1; i++)
+  for (i = 1; i < branch_num; i++)
     {
-      tree cs = TREE_VEC_ELT (cases, i);
+      tree cs = gimple_switch_label (swtch, i);
       basic_block bb = label_to_block (CASE_LABEL (cs));
       edge e;
-      tree phi, high;
+      tree high;
+      gimple_stmt_iterator gsi;
       int j;
 
       if (bb == info.final_bb)
@@ -403,40 +445,139 @@ build_constructors (tree swtch)
 
              elt = VEC_quick_push (constructor_elt,
                                    info.constructors[k], NULL);
-             elt->index = int_const_binop (MINUS_EXPR, pos, info.range_min, 0);
+             elt->index = int_const_binop (MINUS_EXPR, pos,
+                                           info.range_min);
              elt->value = info.default_values[k];
            }
 
-         pos = int_const_binop (PLUS_EXPR, pos, integer_one_node, 0);
+         pos = int_const_binop (PLUS_EXPR, pos, integer_one_node);
        }
-      gcc_assert (tree_int_cst_equal (pos, CASE_LOW(cs)));
+      gcc_assert (tree_int_cst_equal (pos, CASE_LOW (cs)));
 
       j = 0;
       if (CASE_HIGH (cs))
        high = CASE_HIGH (cs);
       else
-       high = CASE_LOW(cs);
-      for (phi = phi_nodes (info.final_bb); phi; phi = PHI_CHAIN (phi))
+       high = CASE_LOW (cs);
+      for (gsi = gsi_start_phis (info.final_bb);
+          !gsi_end_p (gsi); gsi_next (&gsi))
        {
+         gimple phi = gsi_stmt (gsi);
          tree val = PHI_ARG_DEF_FROM_EDGE (phi, e);
+         tree low = CASE_LOW (cs);
          pos = CASE_LOW (cs);
 
-         while (!tree_int_cst_lt (high, pos))
+         do
            {
              constructor_elt *elt;
 
              elt = VEC_quick_push (constructor_elt,
                                    info.constructors[j], NULL);
-             elt->index = int_const_binop (MINUS_EXPR, pos, info.range_min, 0);
+             elt->index = int_const_binop (MINUS_EXPR, pos, info.range_min);
              elt->value = val;
 
-             pos = int_const_binop (PLUS_EXPR, pos, integer_one_node, 0);
-           }
+             pos = int_const_binop (PLUS_EXPR, pos, integer_one_node);
+           } while (!tree_int_cst_lt (high, pos)
+                    && tree_int_cst_lt (low, pos));
          j++;
        }
     }
 }
 
+/* If all values in the constructor vector are the same, return the value.
+   Otherwise return NULL_TREE.  Not supposed to be called for empty
+   vectors.  */
+
+static tree
+constructor_contains_same_values_p (VEC (constructor_elt, gc) *vec)
+{
+  unsigned int i;
+  tree prev = NULL_TREE;
+  constructor_elt *elt;
+
+  FOR_EACH_VEC_ELT (constructor_elt, vec, i, elt)
+    {
+      if (!prev)
+       prev = elt->value;
+      else if (!operand_equal_p (elt->value, prev, OEP_ONLY_CONST))
+       return NULL_TREE;
+    }
+  return prev;
+}
+
+/* Return type which should be used for array elements, either TYPE,
+   or for integral type some smaller integral type that can still hold
+   all the constants.  */
+
+static tree
+array_value_type (gimple swtch, tree type, int num)
+{
+  unsigned int i, len = VEC_length (constructor_elt, info.constructors[num]);
+  constructor_elt *elt;
+  enum machine_mode mode;
+  int sign = 0;
+  tree smaller_type;
+
+  if (!INTEGRAL_TYPE_P (type))
+    return type;
+
+  mode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (TYPE_MODE (type)));
+  if (GET_MODE_SIZE (TYPE_MODE (type)) <= GET_MODE_SIZE (mode))
+    return type;
+
+  if (len < (optimize_bb_for_size_p (gimple_bb (swtch)) ? 2 : 32))
+    return type;
+
+  FOR_EACH_VEC_ELT (constructor_elt, info.constructors[num], i, elt)
+    {
+      double_int cst;
+
+      if (TREE_CODE (elt->value) != INTEGER_CST)
+       return type;
+
+      cst = TREE_INT_CST (elt->value);
+      while (1)
+       {
+         unsigned int prec = GET_MODE_BITSIZE (mode);
+         if (prec > HOST_BITS_PER_WIDE_INT)
+           return type;
+
+         if (sign >= 0
+             && double_int_equal_p (cst, double_int_zext (cst, prec)))
+           {
+             if (sign == 0
+                 && double_int_equal_p (cst, double_int_sext (cst, prec)))
+               break;
+             sign = 1;
+             break;
+           }
+         if (sign <= 0
+             && double_int_equal_p (cst, double_int_sext (cst, prec)))
+           {
+             sign = -1;
+             break;
+           }
+
+         if (sign == 1)
+           sign = 0;
+
+         mode = GET_MODE_WIDER_MODE (mode);
+         if (mode == VOIDmode
+             || GET_MODE_SIZE (mode) >= GET_MODE_SIZE (TYPE_MODE (type)))
+           return type;
+       }
+    }
+
+  if (sign == 0)
+    sign = TYPE_UNSIGNED (type) ? 1 : -1;
+  smaller_type = lang_hooks.types.type_for_mode (mode, sign >= 0);
+  if (GET_MODE_SIZE (TYPE_MODE (type))
+      <= GET_MODE_SIZE (TYPE_MODE (smaller_type)))
+    return type;
+
+  return smaller_type;
+}
+
 /* Create an appropriate array type and declaration and assemble a static array
    variable.  Also create a load statement that initializes the variable in
    question with a value from the static array.  SWTCH is the switch statement
@@ -444,52 +585,72 @@ build_constructors (tree swtch)
    and target SSA names for this particular array.  ARR_INDEX_TYPE is the type
    of the index of the new array, PHI is the phi node of the final BB that
    corresponds to the value that will be loaded from the created array.  TIDX
-   is a temporary variable holding the index for loads from the new array.  */
+   is an ssa name of a temporary variable holding the index for loads from the
+   new array.  */
 
 static void
-build_one_array (tree swtch, int num, tree arr_index_type, tree phi, tree tidx)
+build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi,
+                tree tidx)
 {
-  tree array_type;
-  tree ctor;
-  tree decl;
-  tree value_type;
-  tree name;
-  tree fetch, load;
-  block_stmt_iterator bsi;
+  tree name, cst;
+  gimple load;
+  gimple_stmt_iterator gsi = gsi_for_stmt (swtch);
+  location_t loc = gimple_location (swtch);
 
   gcc_assert (info.default_values[num]);
-  value_type = TREE_TYPE (info.default_values[num]);
-  array_type = build_array_type (value_type, arr_index_type);
 
-  ctor = build_constructor (array_type, info.constructors[num]);
-  TREE_CONSTANT (ctor) = true;
+  name = make_ssa_name (SSA_NAME_VAR (PHI_RESULT (phi)), NULL);
+  info.target_inbound_names[num] = name;
 
-  decl = build_decl (VAR_DECL, NULL_TREE, array_type);
-  TREE_STATIC (decl) = 1;
-  DECL_INITIAL (decl) = ctor;
+  cst = constructor_contains_same_values_p (info.constructors[num]);
+  if (cst)
+    load = gimple_build_assign (name, cst);
+  else
+    {
+      tree array_type, ctor, decl, value_type, fetch, default_type;
 
-  DECL_NAME (decl) = create_tmp_var_name ("CSWTCH");
-  DECL_ARTIFICIAL (decl) = 1;
-  TREE_CONSTANT (decl) = 1;
-  add_referenced_var (decl);
-  assemble_variable (decl, 0, 0, 0);
-  mark_sym_for_renaming (decl);
+      default_type = TREE_TYPE (info.default_values[num]);
+      value_type = array_value_type (swtch, default_type, num);
+      array_type = build_array_type (value_type, arr_index_type);
+      if (default_type != value_type)
+       {
+         unsigned int i;
+         constructor_elt *elt;
 
-  name = make_ssa_name (SSA_NAME_VAR (PHI_RESULT (phi)), NULL_TREE);
-  info.target_inbound_names[num] = name;
+         FOR_EACH_VEC_ELT (constructor_elt, info.constructors[num], i, elt)
+           elt->value = fold_convert (value_type, elt->value);
+       }
+      ctor = build_constructor (array_type, info.constructors[num]);
+      TREE_CONSTANT (ctor) = true;
+      TREE_STATIC (ctor) = true;
+
+      decl = build_decl (loc, VAR_DECL, NULL_TREE, array_type);
+      TREE_STATIC (decl) = 1;
+      DECL_INITIAL (decl) = ctor;
+
+      DECL_NAME (decl) = create_tmp_var_name ("CSWTCH");
+      DECL_ARTIFICIAL (decl) = 1;
+      TREE_CONSTANT (decl) = 1;
+      TREE_READONLY (decl) = 1;
+      add_referenced_var (decl);
+      varpool_mark_needed_node (varpool_node (decl));
+      varpool_finalize_decl (decl);
+
+      fetch = build4 (ARRAY_REF, value_type, decl, tidx, NULL_TREE,
+                     NULL_TREE);
+      if (default_type != value_type)
+       {
+         fetch = fold_convert (default_type, fetch);
+         fetch = force_gimple_operand_gsi (&gsi, fetch, true, NULL_TREE,
+                                           true, GSI_SAME_STMT);
+       }
+      load = gimple_build_assign (name, fetch);
+    }
 
-  fetch = build4 (ARRAY_REF, value_type, decl, tidx, NULL_TREE,
-                 NULL_TREE);
-  load = build2 (GIMPLE_MODIFY_STMT, void_type_node, name, fetch);
   SSA_NAME_DEF_STMT (name) = load;
-
-  bsi = bsi_for_stmt (swtch);
-  bsi_insert_before (&bsi, load, BSI_SAME_STMT);
-  mark_symbols_for_renaming (load);
-
+  gsi_insert_before (&gsi, load, GSI_SAME_STMT);
+  update_stmt (load);
   info.arr_ref_last = load;
-
-  return;
 }
 
 /* Builds and initializes static arrays initialized with values gathered from
@@ -497,52 +658,64 @@ build_one_array (tree swtch, int num, tree arr_index_type, tree phi, tree tidx)
    them.  */
 
 static void
-build_arrays (tree swtch)
+build_arrays (gimple swtch)
 {
   tree arr_index_type;
-  tree tidx, sub;
-  block_stmt_iterator bsi;
-  tree phi = phi_nodes (info.final_bb);
+  tree tidx, sub, tmp, utype;
+  gimple stmt;
+  gimple_stmt_iterator gsi;
   int i;
+  location_t loc = gimple_location (swtch);
 
-  arr_index_type = build_index_type (info.range_size);
-  tidx = make_rename_temp (arr_index_type, "csti");
-  sub = build2 (MINUS_EXPR, TREE_TYPE (info.index_expr), info.index_expr,
-               fold_convert (TREE_TYPE (info.index_expr), info.range_min));
-  sub = build2 (GIMPLE_MODIFY_STMT, void_type_node, tidx, sub);
+  gsi = gsi_for_stmt (swtch);
 
-  bsi = bsi_for_stmt (swtch);
-  bsi_insert_before (&bsi, sub, BSI_SAME_STMT);
-  mark_symbols_for_renaming (sub);
-  info.arr_ref_first = sub;
-
-  for (phi = phi_nodes (info.final_bb), i = 0; phi; phi = PHI_CHAIN (phi), i++)
-    build_one_array (swtch, i, arr_index_type, phi, tidx);
+  /* Make sure we do not generate arithmetics in a subrange.  */
+  utype = TREE_TYPE (info.index_expr);
+  if (TREE_TYPE (utype))
+    utype = lang_hooks.types.type_for_mode (TYPE_MODE (TREE_TYPE (utype)), 1);
+  else
+    utype = lang_hooks.types.type_for_mode (TYPE_MODE (utype), 1);
 
-  return;
+  arr_index_type = build_index_type (info.range_size);
+  tmp = create_tmp_var (utype, "csui");
+  add_referenced_var (tmp);
+  tidx = make_ssa_name (tmp, NULL);
+  sub = fold_build2_loc (loc, MINUS_EXPR, utype,
+                        fold_convert_loc (loc, utype, info.index_expr),
+                        fold_convert_loc (loc, utype, info.range_min));
+  sub = force_gimple_operand_gsi (&gsi, sub,
+                                 false, NULL, true, GSI_SAME_STMT);
+  stmt = gimple_build_assign (tidx, sub);
+  SSA_NAME_DEF_STMT (tidx) = stmt;
+
+  gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
+  update_stmt (stmt);
+  info.arr_ref_first = stmt;
+
+  for (gsi = gsi_start_phis (info.final_bb), i = 0;
+       !gsi_end_p (gsi); gsi_next (&gsi), i++)
+    build_one_array (swtch, i, arr_index_type, gsi_stmt (gsi), tidx);
 }
 
 /* Generates and appropriately inserts loads of default values at the position
    given by BSI.  Returns the last inserted statement.  */
 
-static tree
-gen_def_assigns (block_stmt_iterator *bsi)
+static gimple
+gen_def_assigns (gimple_stmt_iterator *gsi)
 {
   int i;
-  tree assign = NULL_TREE;
+  gimple assign = NULL;
 
   for (i = 0; i < info.phi_count; i++)
     {
-      tree name = make_ssa_name (SSA_NAME_VAR (info.target_inbound_names[i]),
-                                NULL_TREE);
+      tree name
+       = make_ssa_name (SSA_NAME_VAR (info.target_inbound_names[i]), NULL);
 
       info.target_outbound_names[i] = name;
-      assign = build2 (GIMPLE_MODIFY_STMT, void_type_node, name,
-                      info.default_values[i]);
+      assign = gimple_build_assign (name, info.default_values[i]);
       SSA_NAME_DEF_STMT (name) = assign;
-      bsi_insert_before (bsi, assign, BSI_SAME_STMT);
-      find_new_referenced_vars (&assign);
-      mark_symbols_for_renaming (assign);
+      gsi_insert_before (gsi, assign, GSI_SAME_STMT);
+      update_stmt (assign);
     }
   return assign;
 }
@@ -577,13 +750,15 @@ prune_bbs (basic_block bbd, basic_block final)
 static void
 fix_phi_nodes (edge e1f, edge e2f, basic_block bbf)
 {
-  tree phi;
+  gimple_stmt_iterator gsi;
   int i;
 
-  for (phi = phi_nodes (bbf), i = 0; phi; phi = PHI_CHAIN (phi), i++)
+  for (gsi = gsi_start_phis (bbf), i = 0;
+       !gsi_end_p (gsi); gsi_next (&gsi), i++)
     {
-      add_phi_arg (phi, info.target_inbound_names[i], e1f);
-      add_phi_arg (phi, info.target_outbound_names[i], e2f);
+      gimple phi = gsi_stmt (gsi);
+      add_phi_arg (phi, info.target_inbound_names[i], e1f, UNKNOWN_LOCATION);
+      add_phi_arg (phi, info.target_outbound_names[i], e2f, UNKNOWN_LOCATION);
     }
 
 }
@@ -610,74 +785,54 @@ fix_phi_nodes (edge e1f, edge e2f, basic_block bbf)
 */
 
 static void
-gen_inbound_check (tree swtch)
+gen_inbound_check (gimple swtch)
 {
-  tree label_decl1 = create_artificial_label ();
-  tree label_decl2 = create_artificial_label ();
-  tree label_decl3 = create_artificial_label ();
-  tree label1, label2, label3;
-
-  tree utype = unsigned_type_for (TREE_TYPE (info.index_expr));
-  tree tmp_u;
-  tree cast, cast_assign;
-  tree ulb, minus, minus_assign;
+  tree label_decl1 = create_artificial_label (UNKNOWN_LOCATION);
+  tree label_decl2 = create_artificial_label (UNKNOWN_LOCATION);
+  tree label_decl3 = create_artificial_label (UNKNOWN_LOCATION);
+  gimple label1, label2, label3;
+  tree utype, tidx;
   tree bound;
 
-  tree if_expr;
+  gimple cond_stmt;
 
-  tree last_assign;
-  block_stmt_iterator bsi;
+  gimple last_assign;
+  gimple_stmt_iterator gsi;
   basic_block bb0, bb1, bb2, bbf, bbd;
   edge e01, e02, e21, e1d, e1f, e2f;
+  location_t loc = gimple_location (swtch);
 
   gcc_assert (info.default_values);
-  bb0 = bb_for_stmt (swtch);
-
-  /* (end of) block 0 */
-  bsi = bsi_for_stmt (info.arr_ref_first);
-  tmp_u = make_rename_temp (utype, "csui");
-
-  cast = build1 (NOP_EXPR, utype, info.index_expr);
-  cast_assign = build2 (GIMPLE_MODIFY_STMT, void_type_node, tmp_u, cast);
-  find_new_referenced_vars (&cast_assign);
-  bsi_insert_before (&bsi, cast_assign, BSI_SAME_STMT);
-  mark_symbols_for_renaming (cast_assign);
+  bb0 = gimple_bb (swtch);
 
-  ulb = fold_convert (utype, info.range_min);
-  minus = build2 (MINUS_EXPR, utype, tmp_u, ulb);
-  minus_assign = build2 (GIMPLE_MODIFY_STMT, void_type_node, tmp_u, minus);
-  find_new_referenced_vars (&minus_assign);
-  bsi_insert_before (&bsi, minus_assign, BSI_SAME_STMT);
-  mark_symbols_for_renaming (minus_assign);
+  tidx = gimple_assign_lhs (info.arr_ref_first);
+  utype = TREE_TYPE (tidx);
 
-  bound = fold_convert (utype, info.range_size);
-
-  if_expr = build3 (COND_EXPR, void_type_node,
-                   build2 (LE_EXPR, boolean_type_node, tmp_u, bound),
-                   NULL_TREE, NULL_TREE);
+  /* (end of) block 0 */
+  gsi = gsi_for_stmt (info.arr_ref_first);
+  gsi_next (&gsi);
 
-  find_new_referenced_vars (&if_expr);
-  bsi_insert_before (&bsi, if_expr, BSI_SAME_STMT);
-  mark_symbols_for_renaming (if_expr);
+  bound = fold_convert_loc (loc, utype, info.range_size);
+  cond_stmt = gimple_build_cond (LE_EXPR, tidx, bound, NULL_TREE, NULL_TREE);
+  gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT);
+  update_stmt (cond_stmt);
 
   /* block 2 */
-  bsi = bsi_for_stmt (info.arr_ref_first);
-  label2 = build1 (LABEL_EXPR, void_type_node, label_decl2);
-  bsi_insert_before (&bsi, label2, BSI_SAME_STMT);
-  last_assign = gen_def_assigns (&bsi);
+  label2 = gimple_build_label (label_decl2);
+  gsi_insert_before (&gsi, label2, GSI_SAME_STMT);
+  last_assign = gen_def_assigns (&gsi);
 
   /* block 1 */
-  bsi = bsi_for_stmt (info.arr_ref_first);
-  label1 = build1 (LABEL_EXPR, void_type_node, label_decl1);
-  bsi_insert_before (&bsi, label1, BSI_SAME_STMT);
+  label1 = gimple_build_label (label_decl1);
+  gsi_insert_before (&gsi, label1, GSI_SAME_STMT);
 
   /* block F */
-  bsi = bsi_start (info.final_bb);
-  label3 = build1 (LABEL_EXPR, void_type_node, label_decl3);
-  bsi_insert_before (&bsi, label3, BSI_SAME_STMT);
+  gsi = gsi_start_bb (info.final_bb);
+  label3 = gimple_build_label (label_decl3);
+  gsi_insert_before (&gsi, label3, GSI_SAME_STMT);
 
   /* cfg fix */
-  e02 = split_block (bb0, if_expr);
+  e02 = split_block (bb0, cond_stmt);
   bb2 = e02->dest;
 
   e21 = split_block (bb2, last_assign);
@@ -714,8 +869,8 @@ gen_inbound_check (tree swtch)
   bb2->frequency = EDGE_FREQUENCY (e02);
   bbf->frequency = EDGE_FREQUENCY (e1f) + EDGE_FREQUENCY (e2f);
 
-  prune_bbs (bbd, info.final_bb); /* to keep calc_dfs_tree() in dominance.c
-                                    happy */
+  prune_bbs (bbd, info.final_bb); /* To keep calc_dfs_tree() in dominance.c
+                                    happy */
 
   fix_phi_nodes (e1f, e2f, bbf);
 
@@ -728,34 +883,31 @@ gen_inbound_check (tree swtch)
    one after another until one fails or the conversion is completed.  */
 
 static bool
-process_switch (tree swtch)
+process_switch (gimple swtch)
 {
-  int i;
-  tree cases;
+  unsigned int i, branch_num = gimple_switch_num_labels (swtch);
   tree index_type;
 
   /* Operand 2 is either NULL_TREE or a vector of cases (stmt.c).  */
-  if (TREE_OPERAND (swtch, 2) == NULL_TREE)
+  if (branch_num < 2)
     {
-      info.reason = "swtch has no labels\n";
+      info.reason = "switch has no labels\n";
       return false;
     }
 
-  /* Comment from stmt.c:
-     The switch body is lowered in gimplify.c, we should never have switches
-     with a non-NULL SWITCH_BODY here.  */
-  gcc_assert (!SWITCH_BODY (swtch));
-
-  cases = SWITCH_LABELS (swtch);
   info.final_bb = NULL;
-  info.switch_bb = bb_for_stmt (swtch);
-  info.index_expr = SWITCH_COND (swtch);
+  info.switch_bb = gimple_bb (swtch);
+  info.index_expr = gimple_switch_index (swtch);
   index_type = TREE_TYPE (info.index_expr);
-  info.arr_ref_first = NULL_TREE;
-  info.arr_ref_last = NULL_TREE;
+  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) */
@@ -771,13 +923,22 @@ process_switch (tree swtch)
 
   /* For all the cases, see whether they are empty, the assignments they
      represent constant and so on...  */
-  for (i = 0; i < TREE_VEC_LENGTH (cases); i++)
+  for (i = 0; i < branch_num; i++)
+    if (!check_process_case (gimple_switch_label (swtch, i)))
+      {
+       if (dump_file)
+         fprintf (dump_file, "Processing of case %i failed\n", i);
+       return false;
+      }
+
+  if (info.bit_test_uniq <= 2)
     {
-      tree part_case = TREE_VEC_ELT (cases, i);
-      if (!check_process_case (part_case))
+      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))
        {
-         if (dump_file)
-           fprintf (dump_file, "Processing of case %i failed\n", i);
+         info.reason = "  Expanding as bit test is preferable\n";
          return false;
        }
     }
@@ -789,11 +950,11 @@ process_switch (tree swtch)
      transformation.  */
 
   create_temp_arrays ();
-  gather_default_values (TREE_VEC_ELT (cases, TREE_VEC_LENGTH (cases) - 1));
+  gather_default_values (gimple_switch_label (swtch, 0));
   build_constructors (swtch);
 
   build_arrays (swtch); /* Build the static arrays and assignments.   */
-  gen_inbound_check (swtch);   /* Build the bounds check.  */
+  gen_inbound_check (swtch);   /* Build the bounds check.  */
 
   /* Cleanup:  */
   free_temp_arrays ();
@@ -810,18 +971,18 @@ do_switchconv (void)
 
   FOR_EACH_BB (bb)
   {
-    tree stmt = last_stmt (bb);
-    if (stmt && TREE_CODE (stmt) == SWITCH_EXPR)
+    gimple stmt = last_stmt (bb);
+    if (stmt && gimple_code (stmt) == GIMPLE_SWITCH)
       {
-       expanded_location loc = expand_location (EXPR_LOCATION (stmt));
-
        if (dump_file)
          {
+           expanded_location loc = expand_location (gimple_location (stmt));
+
            fprintf (dump_file, "beginning to process the following "
                     "SWITCH statement (%s:%d) : ------- \n",
                     loc.file, loc.line);
-           print_generic_stmt (dump_file, stmt, 2);
-           fprintf (dump_file, "\n");
+           print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+           putc ('\n', dump_file);
          }
 
        info.reason = NULL;
@@ -829,8 +990,8 @@ do_switchconv (void)
          {
            if (dump_file)
              {
-               fprintf (dump_file, "Switch converted\n");
-               fprintf (dump_file, "--------------------------------\n");
+               fputs ("Switch converted\n", dump_file);
+               fputs ("--------------------------------\n", dump_file);
              }
          }
        else
@@ -838,9 +999,9 @@ do_switchconv (void)
            if (dump_file)
              {
                gcc_assert (info.reason);
-               fprintf (dump_file, "Bailing out - ");
-               fprintf (dump_file, info.reason);
-               fprintf (dump_file, "--------------------------------\n");
+               fputs ("Bailing out - ", dump_file);
+               fputs (info.reason, dump_file);
+               fputs ("--------------------------------\n", dump_file);
              }
          }
       }
@@ -862,17 +1023,17 @@ struct gimple_opt_pass pass_convert_switch =
  {
   GIMPLE_PASS,
   "switchconv",                                /* name */
-  switchconv_gate,                     /* gate */
+  switchconv_gate,                     /* gate */
   do_switchconv,                       /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
-  0,                                   /* tv_id */
+  TV_TREE_SWITCH_CONVERSION,           /* tv_id */
   PROP_cfg | PROP_ssa,                 /* properties_required */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_update_ssa | TODO_dump_func
+  TODO_update_ssa 
   | TODO_ggc_collect | TODO_verify_ssa  /* todo_flags_finish */
  }
 };