Wunused-parameter warnings are given from cgraph::finalize_function,
[gcc.git] / gcc / tree-switch-conversion.c
index de8c9e874d6c84205483c76f942eb2e242d3f619..2f9ad27d31acc9708572fb52eafb30871d7946f9 100644 (file)
@@ -1,7 +1,6 @@
 /* Lower GIMPLE_SWITCH expressions to something more efficient than
    a jump table.
-   Copyright (C) 2006, 2008, 2009, 2010, 2011, 2012
-   Free Software Foundation, Inc.
+   Copyright (C) 2006-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -27,22 +26,53 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "line-map.h"
 #include "params.h"
 #include "flags.h"
+#include "alias.h"
+#include "symtab.h"
 #include "tree.h"
+#include "fold-const.h"
+#include "varasm.h"
+#include "stor-layout.h"
+#include "predict.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
 #include "basic-block.h"
-#include "tree-flow.h"
-#include "tree-flow-inline.h"
-#include "tree-ssa-operands.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "gimple.h"
+#include "gimplify.h"
+#include "gimple-iterator.h"
+#include "gimplify-me.h"
+#include "gimple-ssa.h"
+#include "cgraph.h"
+#include "tree-cfg.h"
+#include "tree-phinodes.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
 #include "tree-pass.h"
 #include "gimple-pretty-print.h"
-#include "tree-dump.h"
-#include "timevar.h"
+#include "cfgloop.h"
+
+/* ??? For lang_hooks.types.type_for_mode, but is there a word_mode
+   type in the GIMPLE type system that is language-independent?  */
 #include "langhooks.h"
 
 /* Need to include expr.h and optabs.h for lshift_cheap_p.  */
+#include "rtl.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
 #include "expr.h"
+#include "insn-codes.h"
 #include "optabs.h"
 \f
 /* Maximum number of case bit tests.
@@ -71,7 +101,7 @@ hoist_edge_and_branch_if_true (gimple_stmt_iterator *gsip,
                               bool update_dominators)
 {
   tree tmp;
-  gimple cond_stmt;
+  gcond *cond_stmt;
   edge e_false;
   basic_block new_bb, split_bb = gsi_bb (*gsip);
   bool dominated_e_true = false;
@@ -111,38 +141,6 @@ hoist_edge_and_branch_if_true (gimple_stmt_iterator *gsip,
 }
 
 
-/* Determine whether "1 << x" is relatively cheap in word_mode.  */
-/* FIXME: This is the function that we need rtl.h and optabs.h for.
-   This function (and similar RTL-related cost code in e.g. IVOPTS) should
-   be moved to some kind of interface file for GIMPLE/RTL interactions.  */
-static bool
-lshift_cheap_p (void)
-{
-  /* FIXME: This should be made target dependent via this "this_target"
-     mechanism, similar to e.g. can_copy_init_p in gcse.c.  */
-  static bool init[2] = {false, false};
-  static bool cheap[2] = {true, true};
-  bool speed_p;
-
-  /* If the targer has no lshift in word_mode, the operation will most
-     probably not be cheap.  ??? Does GCC even work for such targets?  */
-  if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing)
-    return false;
-
-  speed_p = optimize_insn_for_speed_p ();
-
-  if (!init[speed_p])
-    {
-      rtx reg = gen_raw_REG (word_mode, 10000);
-      int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg),
-                              speed_p);
-      cheap[speed_p] = cost < COSTS_N_INSNS (MAX_CASE_BIT_TESTS);
-      init[speed_p] = true;
-    }
-
-  return cheap[speed_p];
-}
-
 /* Return true if a switch should be expanded as a bit test.
    RANGE is the difference between highest and lowest case.
    UNIQ is number of unique case node targets, not counting the default case.
@@ -151,12 +149,12 @@ lshift_cheap_p (void)
 static bool
 expand_switch_using_bit_tests_p (tree range,
                                 unsigned int uniq,
-                                unsigned int count)
+                                unsigned int count, bool speed_p)
 {
   return (((uniq == 1 && count >= 3)
           || (uniq == 2 && count >= 5)
           || (uniq == 3 && count >= 6))
-         && lshift_cheap_p ()
+         && lshift_cheap_p (speed_p)
          && compare_tree_int (range, GET_MODE_BITSIZE (word_mode)) < 0
          && compare_tree_int (range, 0) > 0);
 }
@@ -175,7 +173,7 @@ as a single bit test:
        if ((1<<x) & ((1<<4)|(1<<6)|(1<<9)|(1<<11)))
 
 This transformation is only applied if the number of case targets is small,
-if CST constains at least 3 bits, and "x << 1" is cheap.  The bit tests are
+if CST constains at least 3 bits, and "1 << x" is cheap.  The bit tests are
 performed in "word_mode".
 
 The following example shows the code the transformation generates:
@@ -235,8 +233,7 @@ This transformation was contributed by Roger Sayle, see this e-mail:
 
 struct case_bit_test
 {
-  HOST_WIDE_INT hi;
-  HOST_WIDE_INT lo;
+  wide_int mask;
   edge target_edge;
   tree label;
   int bits;
@@ -283,13 +280,14 @@ case_bit_test_cmp (const void *p1, const void *p2)
     are not guaranteed to be of the same type as INDEX_EXPR
     (the gimplifier doesn't change the type of case label values,
     and MINVAL and RANGE are derived from those values).
+    MAXVAL is MINVAL + RANGE.
 
     There *MUST* be MAX_CASE_BIT_TESTS or less unique case
     node targets.  */
 
 static void
-emit_case_bit_tests (gimple swtch, tree index_expr,
-                    tree minval, tree range)
+emit_case_bit_tests (gswitch *swtch, tree index_expr,
+                    tree minval, tree range, tree maxval)
 {
   struct case_bit_test test[MAX_CASE_BIT_TESTS];
   unsigned int i, j, k;
@@ -300,24 +298,26 @@ emit_case_bit_tests (gimple swtch, tree index_expr,
   edge default_edge;
   bool update_dom = dom_info_available_p (CDI_DOMINATORS);
 
-  VEC (basic_block, heap) *bbs_to_fix_dom = NULL;
+  vec<basic_block> bbs_to_fix_dom = vNULL;
 
   tree index_type = TREE_TYPE (index_expr);
   tree unsigned_index_type = unsigned_type_for (index_type);
   unsigned int branch_num = gimple_switch_num_labels (swtch);
 
   gimple_stmt_iterator gsi;
-  gimple shift_stmt;
+  gassign *shift_stmt;
 
   tree idx, tmp, csui;
   tree word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
   tree word_mode_zero = fold_convert (word_type_node, integer_zero_node);
   tree word_mode_one = fold_convert (word_type_node, integer_one_node);
+  int prec = TYPE_PRECISION (word_type_node);
+  wide_int wone = wi::one (prec);
 
   memset (&test, 0, sizeof (test));
 
   /* Get the edge for the default case.  */
-  tmp = gimple_switch_label (swtch, 0);
+  tmp = gimple_switch_default_label (swtch);
   default_bb = label_to_block (CASE_LABEL (tmp));
   default_edge = find_edge (switch_bb, default_bb);
 
@@ -329,17 +329,15 @@ emit_case_bit_tests (gimple swtch, tree index_expr,
       unsigned int lo, hi;
       tree cs = gimple_switch_label (swtch, i);
       tree label = CASE_LABEL (cs);
+      edge e = find_edge (switch_bb, label_to_block (label));
       for (k = 0; k < count; k++)
-       if (label == test[k].label)
+       if (e == test[k].target_edge)
          break;
 
       if (k == count)
        {
-         edge e = find_edge (switch_bb, label_to_block (label));
-         gcc_assert (e);
          gcc_checking_assert (count < MAX_CASE_BIT_TESTS);
-         test[k].hi = 0;
-         test[k].lo = 0;
+         test[k].mask = wi::zero (prec);
          test[k].target_edge = e;
          test[k].label = label;
          test[k].bits = 1;
@@ -348,24 +346,47 @@ emit_case_bit_tests (gimple swtch, tree index_expr,
       else
         test[k].bits++;
 
-      lo = tree_low_cst (int_const_binop (MINUS_EXPR,
-                                         CASE_LOW (cs), minval),
-                        1);
+      lo = tree_to_uhwi (int_const_binop (MINUS_EXPR,
+                                         CASE_LOW (cs), minval));
       if (CASE_HIGH (cs) == NULL_TREE)
        hi = lo;
       else
-       hi = tree_low_cst (int_const_binop (MINUS_EXPR, 
-                                           CASE_HIGH (cs), minval),
-                          1);
+       hi = tree_to_uhwi (int_const_binop (MINUS_EXPR,
+                                           CASE_HIGH (cs), minval));
 
       for (j = lo; j <= hi; j++)
-        if (j >= HOST_BITS_PER_WIDE_INT)
-         test[k].hi |= (HOST_WIDE_INT) 1 << (j - HOST_BITS_PER_INT);
-       else
-         test[k].lo |= (HOST_WIDE_INT) 1 << j;
+       test[k].mask |= wi::lshift (wone, j);
     }
 
-  qsort (test, count, sizeof(*test), case_bit_test_cmp);
+  qsort (test, count, sizeof (*test), case_bit_test_cmp);
+
+  /* If all values are in the 0 .. BITS_PER_WORD-1 range, we can get rid of
+     the minval subtractions, but it might make the mask constants more
+     expensive.  So, compare the costs.  */
+  if (compare_tree_int (minval, 0) > 0
+      && compare_tree_int (maxval, GET_MODE_BITSIZE (word_mode)) < 0)
+    {
+      int cost_diff;
+      HOST_WIDE_INT m = tree_to_uhwi (minval);
+      rtx reg = gen_raw_REG (word_mode, 10000);
+      bool speed_p = optimize_bb_for_speed_p (gimple_bb (swtch));
+      cost_diff = set_rtx_cost (gen_rtx_PLUS (word_mode, reg,
+                                             GEN_INT (-m)), speed_p);
+      for (i = 0; i < count; i++)
+       {
+         rtx r = immed_wide_int_const (test[i].mask, word_mode);
+         cost_diff += set_src_cost (gen_rtx_AND (word_mode, reg, r), speed_p);
+         r = immed_wide_int_const (wi::lshift (test[i].mask, m), word_mode);
+         cost_diff -= set_src_cost (gen_rtx_AND (word_mode, reg, r), speed_p);
+       }
+      if (cost_diff > 0)
+       {
+         for (i = 0; i < count; i++)
+           test[i].mask = wi::lshift (test[i].mask, m);
+         minval = build_zero_cst (TREE_TYPE (minval));
+         range = maxval;
+       }
+    }
 
   /* We generate two jumps to the default case label.
      Split the default edge, so that we don't have to do any PHI node
@@ -374,20 +395,20 @@ emit_case_bit_tests (gimple swtch, tree index_expr,
 
   if (update_dom)
     {
-      bbs_to_fix_dom = VEC_alloc (basic_block, heap, 10);
-      VEC_quick_push (basic_block, bbs_to_fix_dom, switch_bb);
-      VEC_quick_push (basic_block, bbs_to_fix_dom, default_bb);
-      VEC_quick_push (basic_block, bbs_to_fix_dom, new_default_bb);
+      bbs_to_fix_dom.create (10);
+      bbs_to_fix_dom.quick_push (switch_bb);
+      bbs_to_fix_dom.quick_push (default_bb);
+      bbs_to_fix_dom.quick_push (new_default_bb);
     }
 
   /* Now build the test-and-branch code.  */
 
   gsi = gsi_last_bb (switch_bb);
 
-  /* idx = (unsigned) (x - minval) */
-  idx = fold_build2 (MINUS_EXPR, index_type, index_expr,
-                    fold_convert (index_type, minval));
-  idx = fold_convert (unsigned_index_type, idx);
+  /* idx = (unsigned)x - minval.  */
+  idx = fold_convert (unsigned_index_type, index_expr);
+  idx = fold_build2 (MINUS_EXPR, unsigned_index_type, idx,
+                    fold_convert (unsigned_index_type, minval));
   idx = force_gimple_operand_gsi (&gsi, idx,
                                  /*simple=*/true, NULL_TREE,
                                  /*before=*/true, GSI_SAME_STMT);
@@ -400,7 +421,7 @@ emit_case_bit_tests (gimple swtch, tree index_expr,
   tmp = fold_build2 (GT_EXPR, boolean_type_node, idx, range);
   new_bb = hoist_edge_and_branch_if_true (&gsi, tmp, default_edge, update_dom);
   if (update_dom)
-    VEC_quick_push (basic_block, bbs_to_fix_dom, new_bb);
+    bbs_to_fix_dom.quick_push (new_bb);
   gcc_assert (gimple_bb (swtch) == new_bb);
   gsi = gsi_last_bb (new_bb);
 
@@ -408,32 +429,29 @@ emit_case_bit_tests (gimple swtch, tree index_expr,
      of NEW_BB, are still immediately dominated by SWITCH_BB.  Make it so.  */
   if (update_dom)
     {
-      VEC (basic_block, heap) *dom_bbs;
+      vec<basic_block> dom_bbs;
       basic_block dom_son;
 
       dom_bbs = get_dominated_by (CDI_DOMINATORS, new_bb);
-      FOR_EACH_VEC_ELT (basic_block, dom_bbs, i, dom_son)
+      FOR_EACH_VEC_ELT (dom_bbs, i, dom_son)
        {
          edge e = find_edge (new_bb, dom_son);
          if (e && single_pred_p (e->dest))
            continue;
          set_immediate_dominator (CDI_DOMINATORS, dom_son, switch_bb);
-         VEC_safe_push (basic_block, heap, bbs_to_fix_dom, dom_son);
+         bbs_to_fix_dom.safe_push (dom_son);
        }
-      VEC_free (basic_block, heap, dom_bbs);
+      dom_bbs.release ();
     }
 
   /* csui = (1 << (word_mode) idx) */
-  tmp = create_tmp_var (word_type_node, "csui");
-  add_referenced_var (tmp);
-  csui = make_ssa_name (tmp, NULL);
+  csui = make_ssa_name (word_type_node);
   tmp = fold_build2 (LSHIFT_EXPR, word_type_node, word_mode_one,
                     fold_convert (word_type_node, idx));
   tmp = force_gimple_operand_gsi (&gsi, tmp,
                                  /*simple=*/false, NULL_TREE,
                                  /*before=*/true, GSI_SAME_STMT);
   shift_stmt = gimple_build_assign (csui, tmp);
-  SSA_NAME_DEF_STMT (csui) = shift_stmt;
   gsi_insert_before (&gsi, shift_stmt, GSI_SAME_STMT);
   update_stmt (shift_stmt);
 
@@ -441,7 +459,7 @@ emit_case_bit_tests (gimple swtch, tree index_expr,
         if (const & csui) goto target  */
   for (k = 0; k < count; k++)
     {
-      tmp = build_int_cst_wide (word_type_node, test[k].lo, test[k].hi);
+      tmp = wide_int_to_tree (word_type_node, test[k].mask);
       tmp = fold_build2 (BIT_AND_EXPR, word_type_node, csui, tmp);
       tmp = force_gimple_operand_gsi (&gsi, tmp,
                                      /*simple=*/true, NULL_TREE,
@@ -450,7 +468,7 @@ emit_case_bit_tests (gimple swtch, tree index_expr,
       new_bb = hoist_edge_and_branch_if_true (&gsi, tmp, test[k].target_edge,
                                              update_dom);
       if (update_dom)
-       VEC_safe_push (basic_block, heap, bbs_to_fix_dom, new_bb);
+       bbs_to_fix_dom.safe_push (new_bb);
       gcc_assert (gimple_bb (swtch) == new_bb);
       gsi = gsi_last_bb (new_bb);
     }
@@ -468,7 +486,7 @@ emit_case_bit_tests (gimple swtch, tree index_expr,
     {
       /* Fix up the dominator tree.  */
       iterate_fix_dominators (CDI_DOMINATORS, bbs_to_fix_dom, true);
-      VEC_free (basic_block, heap, bbs_to_fix_dom);
+      bbs_to_fix_dom.release ();
     }
 }
 \f
@@ -574,7 +592,7 @@ struct switch_conv_info
   tree *default_values;
 
   /* Constructors of new static arrays.  */
-  VEC (constructor_elt, gc) **constructors;
+  vec<constructor_elt, va_gc> **constructors;
 
   /* Array of ssa names that are initialized with a value from a new static
      array.  */
@@ -604,7 +622,7 @@ struct switch_conv_info
 /* Collect information about GIMPLE_SWITCH statement SWTCH into INFO.  */
 
 static void
-collect_switch_conv_info (gimple swtch, struct switch_conv_info *info)
+collect_switch_conv_info (gswitch *swtch, struct switch_conv_info *info)
 {
   unsigned int branch_num = gimple_switch_num_labels (swtch);
   tree min_case, max_case;
@@ -615,14 +633,12 @@ collect_switch_conv_info (gimple swtch, struct switch_conv_info *info)
   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);
-
-  /* Collect the bits we can deduce from the CFG.  */
+     is a default label which is the first in the vector.
+     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)));
+    label_to_block (CASE_LABEL (gimple_switch_default_label (swtch)));
   e_default = find_edge (info->switch_bb, info->default_bb);
   info->default_prob = e_default->probability;
   info->default_count = e_default->count;
@@ -631,15 +647,16 @@ collect_switch_conv_info (gimple swtch, struct switch_conv_info *info)
       info->other_count += e->count;
 
   /* 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;
-       }
-    }
+     targets.  If it exists, record it in FINAL_BB.
+     Start with the destination of the default case as guess
+     or its destination in case it is a forwarder block.  */
+  if (! single_pred_p (e_default->dest))
+    info->final_bb = e_default->dest;
+  else if (single_succ_p (e_default->dest)
+          && ! single_pred_p (single_succ (e_default->dest)))
+    info->final_bb = single_succ (e_default->dest);
+  /* Require that all switch destinations are either that common
+     FINAL_BB or a forwarder to it.  */
   if (info->final_bb)
     FOR_EACH_EDGE (e, ei, info->switch_bb->succs)
       {
@@ -696,13 +713,13 @@ static bool
 check_range (struct switch_conv_info *info)
 {
   gcc_assert (info->range_size);
-  if (!host_integerp (info->range_size, 1))
+  if (!tree_fits_uhwi_p (info->range_size))
     {
       info->reason = "index range way too large or otherwise unusable";
       return false;
     }
 
-  if ((unsigned HOST_WIDE_INT) tree_low_cst (info->range_size, 1)
+  if (tree_to_uhwi (info->range_size)
       > ((unsigned) info->count * SWITCH_CONVERSION_BRANCH_RATIO))
     {
       info->reason = "the maximum range-branch ratio exceeded";
@@ -743,12 +760,12 @@ check_all_empty_except_final (struct switch_conv_info *info)
 static bool
 check_final_bb (struct switch_conv_info *info)
 {
-  gimple_stmt_iterator gsi;
+  gphi_iterator gsi;
 
   info->phi_count = 0;
   for (gsi = gsi_start_phis (info->final_bb); !gsi_end_p (gsi); gsi_next (&gsi))
     {
-      gimple phi = gsi_stmt (gsi);
+      gphi *phi = gsi.phi ();
       unsigned int i;
 
       info->phi_count++;
@@ -797,12 +814,14 @@ create_temp_arrays (struct switch_conv_info *info)
   int i;
 
   info->default_values = XCNEWVEC (tree, info->phi_count * 3);
-  info->constructors = XCNEWVEC (VEC (constructor_elt, gc) *, info->phi_count);
+  /* ??? Macros do not support multi argument templates in their
+     argument list.  We create a typedef to work around that problem.  */
+  typedef vec<constructor_elt, va_gc> *vec_constructor_elt_gc;
+  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);
+    vec_alloc (info->constructors[i], tree_to_uhwi (info->range_size) + 1);
 }
 
 /* Free the arrays created by create_temp_arrays().  The vectors that are
@@ -822,7 +841,7 @@ free_temp_arrays (struct switch_conv_info *info)
 static void
 gather_default_values (tree default_case, struct switch_conv_info *info)
 {
-  gimple_stmt_iterator gsi;
+  gphi_iterator gsi;
   basic_block bb = label_to_block (CASE_LABEL (default_case));
   edge e;
   int i = 0;
@@ -836,7 +855,7 @@ gather_default_values (tree default_case, struct switch_conv_info *info)
 
   for (gsi = gsi_start_phis (info->final_bb); !gsi_end_p (gsi); gsi_next (&gsi))
     {
-      gimple phi = gsi_stmt (gsi);
+      gphi *phi = gsi.phi ();
       tree val = PHI_ARG_DEF_FROM_EDGE (phi, e);
       gcc_assert (val);
       info->default_values[i++] = val;
@@ -848,7 +867,7 @@ gather_default_values (tree default_case, struct switch_conv_info *info)
    order of phi nodes.  SWTCH is the switch statement being converted.  */
 
 static void
-build_constructors (gimple swtch, struct switch_conv_info *info)
+build_constructors (gswitch *swtch, struct switch_conv_info *info)
 {
   unsigned i, branch_num = gimple_switch_num_labels (swtch);
   tree pos = info->range_min;
@@ -859,7 +878,7 @@ build_constructors (gimple swtch, struct switch_conv_info *info)
       basic_block bb = label_to_block (CASE_LABEL (cs));
       edge e;
       tree high;
-      gimple_stmt_iterator gsi;
+      gphi_iterator gsi;
       int j;
 
       if (bb == info->final_bb)
@@ -873,16 +892,16 @@ build_constructors (gimple swtch, struct switch_conv_info *info)
          int k;
          for (k = 0; k < info->phi_count; k++)
            {
-             constructor_elt *elt;
+             constructor_elt elt;
 
-             elt = VEC_quick_push (constructor_elt,
-                                   info->constructors[k], NULL);
-             elt->index = int_const_binop (MINUS_EXPR, pos,
-                                           info->range_min);
-             elt->value = info->default_values[k];
+             elt.index = int_const_binop (MINUS_EXPR, pos, info->range_min);
+             elt.value
+               = unshare_expr_without_location (info->default_values[k]);
+             info->constructors[k]->quick_push (elt);
            }
 
-         pos = int_const_binop (PLUS_EXPR, pos, integer_one_node);
+         pos = int_const_binop (PLUS_EXPR, pos,
+                                build_int_cst (TREE_TYPE (pos), 1));
        }
       gcc_assert (tree_int_cst_equal (pos, CASE_LOW (cs)));
 
@@ -894,21 +913,21 @@ build_constructors (gimple swtch, struct switch_conv_info *info)
       for (gsi = gsi_start_phis (info->final_bb);
           !gsi_end_p (gsi); gsi_next (&gsi))
        {
-         gimple phi = gsi_stmt (gsi);
+         gphi *phi = gsi.phi ();
          tree val = PHI_ARG_DEF_FROM_EDGE (phi, e);
          tree low = CASE_LOW (cs);
          pos = CASE_LOW (cs);
 
          do
            {
-             constructor_elt *elt;
+             constructor_elt elt;
 
-             elt = VEC_quick_push (constructor_elt,
-                                   info->constructors[j], NULL);
-             elt->index = int_const_binop (MINUS_EXPR, pos, info->range_min);
-             elt->value = val;
+             elt.index = int_const_binop (MINUS_EXPR, pos, info->range_min);
+             elt.value = unshare_expr_without_location (val);
+             info->constructors[j]->quick_push (elt);
 
-             pos = int_const_binop (PLUS_EXPR, pos, integer_one_node);
+             pos = int_const_binop (PLUS_EXPR, pos,
+                                    build_int_cst (TREE_TYPE (pos), 1));
            } while (!tree_int_cst_lt (high, pos)
                     && tree_int_cst_lt (low, pos));
          j++;
@@ -921,13 +940,13 @@ build_constructors (gimple swtch, struct switch_conv_info *info)
    vectors.  */
 
 static tree
-constructor_contains_same_values_p (VEC (constructor_elt, gc) *vec)
+constructor_contains_same_values_p (vec<constructor_elt, va_gc> *vec)
 {
   unsigned int i;
   tree prev = NULL_TREE;
   constructor_elt *elt;
 
-  FOR_EACH_VEC_ELT (constructor_elt, vec, i, elt)
+  FOR_EACH_VEC_SAFE_ELT (vec, i, elt)
     {
       if (!prev)
        prev = elt->value;
@@ -942,12 +961,12 @@ constructor_contains_same_values_p (VEC (constructor_elt, gc) *vec)
    all the constants.  */
 
 static tree
-array_value_type (gimple swtch, tree type, int num,
+array_value_type (gswitch *swtch, tree type, int num,
                  struct switch_conv_info *info)
 {
-  unsigned int i, len = VEC_length (constructor_elt, info->constructors[num]);
+  unsigned int i, len = vec_safe_length (info->constructors[num]);
   constructor_elt *elt;
-  enum machine_mode mode;
+  machine_mode mode;
   int sign = 0;
   tree smaller_type;
 
@@ -961,31 +980,28 @@ array_value_type (gimple swtch, tree type, int num,
   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)
+  FOR_EACH_VEC_SAFE_ELT (info->constructors[num], i, elt)
     {
-      double_int cst;
+      wide_int cst;
 
       if (TREE_CODE (elt->value) != INTEGER_CST)
        return type;
 
-      cst = TREE_INT_CST (elt->value);
+      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 && cst == wi::zext (cst, prec))
            {
-             if (sign == 0
-                 && double_int_equal_p (cst, double_int_sext (cst, prec)))
+             if (sign == 0 && cst == wi::sext (cst, prec))
                break;
              sign = 1;
              break;
            }
-         if (sign <= 0
-             && double_int_equal_p (cst, double_int_sext (cst, prec)))
+         if (sign <= 0 && cst == wi::sext (cst, prec))
            {
              sign = -1;
              break;
@@ -1022,8 +1038,8 @@ array_value_type (gimple swtch, tree type, int num,
    new array.  */
 
 static void
-build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi,
-                tree tidx, struct switch_conv_info *info)
+build_one_array (gswitch *swtch, int num, tree arr_index_type,
+                gphi *phi, tree tidx, struct switch_conv_info *info)
 {
   tree name, cst;
   gimple load;
@@ -1032,7 +1048,7 @@ build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi,
 
   gcc_assert (info->default_values[num]);
 
-  name = make_ssa_name (SSA_NAME_VAR (PHI_RESULT (phi)), NULL);
+  name = copy_ssa_name (PHI_RESULT (phi));
   info->target_inbound_names[num] = name;
 
   cst = constructor_contains_same_values_p (info->constructors[num]);
@@ -1050,7 +1066,7 @@ build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi,
          unsigned int i;
          constructor_elt *elt;
 
-         FOR_EACH_VEC_ELT (constructor_elt, info->constructors[num], i, elt)
+         FOR_EACH_VEC_SAFE_ELT (info->constructors[num], i, elt)
            elt->value = fold_convert (value_type, elt->value);
        }
       ctor = build_constructor (array_type, info->constructors[num]);
@@ -1063,9 +1079,11 @@ build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi,
 
       DECL_NAME (decl) = create_tmp_var_name ("CSWTCH");
       DECL_ARTIFICIAL (decl) = 1;
+      DECL_IGNORED_P (decl) = 1;
       TREE_CONSTANT (decl) = 1;
       TREE_READONLY (decl) = 1;
-      varpool_finalize_decl (decl);
+      DECL_IGNORED_P (decl) = 1;
+      varpool_node::finalize_decl (decl);
 
       fetch = build4 (ARRAY_REF, value_type, decl, tidx, NULL_TREE,
                      NULL_TREE);
@@ -1078,7 +1096,6 @@ build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi,
       load = gimple_build_assign (name, fetch);
     }
 
-  SSA_NAME_DEF_STMT (name) = load;
   gsi_insert_before (&gsi, load, GSI_SAME_STMT);
   update_stmt (load);
   info->arr_ref_last = load;
@@ -1089,12 +1106,13 @@ build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi,
    them.  */
 
 static void
-build_arrays (gimple swtch, struct switch_conv_info *info)
+build_arrays (gswitch *swtch, struct switch_conv_info *info)
 {
   tree arr_index_type;
-  tree tidx, sub, tmp, utype;
+  tree tidx, sub, utype;
   gimple stmt;
   gimple_stmt_iterator gsi;
+  gphi_iterator gpi;
   int i;
   location_t loc = gimple_location (swtch);
 
@@ -1108,43 +1126,37 @@ build_arrays (gimple swtch, struct switch_conv_info *info)
     utype = lang_hooks.types.type_for_mode (TYPE_MODE (utype), 1);
 
   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);
+  tidx = make_ssa_name (utype);
   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, info);
+  for (gpi = gsi_start_phis (info->final_bb), i = 0;
+       !gsi_end_p (gpi); gsi_next (&gpi), i++)
+    build_one_array (swtch, i, arr_index_type, gpi.phi (), tidx, info);
 }
 
 /* Generates and appropriately inserts loads of default values at the position
    given by BSI.  Returns the last inserted statement.  */
 
-static gimple
+static gassign *
 gen_def_assigns (gimple_stmt_iterator *gsi, struct switch_conv_info *info)
 {
   int i;
-  gimple assign = NULL;
+  gassign *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 name = copy_ssa_name (info->target_inbound_names[i]);
       info->target_outbound_names[i] = name;
       assign = gimple_build_assign (name, info->default_values[i]);
-      SSA_NAME_DEF_STMT (name) = assign;
       gsi_insert_before (gsi, assign, GSI_SAME_STMT);
       update_stmt (assign);
     }
@@ -1182,13 +1194,13 @@ static void
 fix_phi_nodes (edge e1f, edge e2f, basic_block bbf,
               struct switch_conv_info *info)
 {
-  gimple_stmt_iterator gsi;
+  gphi_iterator gsi;
   int i;
 
   for (gsi = gsi_start_phis (bbf), i = 0;
        !gsi_end_p (gsi); gsi_next (&gsi), i++)
     {
-      gimple phi = gsi_stmt (gsi);
+      gphi *phi = gsi.phi ();
       add_phi_arg (phi, info->target_inbound_names[i], e1f, UNKNOWN_LOCATION);
       add_phi_arg (phi, info->target_outbound_names[i], e2f, UNKNOWN_LOCATION);
     }
@@ -1216,18 +1228,18 @@ fix_phi_nodes (edge e1f, edge e2f, basic_block bbf,
 */
 
 static void
-gen_inbound_check (gimple swtch, struct switch_conv_info *info)
+gen_inbound_check (gswitch *swtch, struct switch_conv_info *info)
 {
   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;
+  glabel *label1, *label2, *label3;
   tree utype, tidx;
   tree bound;
 
-  gimple cond_stmt;
+  gcond *cond_stmt;
 
-  gimple last_assign;
+  gassign *last_assign;
   gimple_stmt_iterator gsi;
   basic_block bb0, bb1, bb2, bbf, bbd;
   edge e01, e02, e21, e1d, e1f, e2f;
@@ -1310,7 +1322,7 @@ gen_inbound_check (gimple swtch, struct switch_conv_info *info)
   /* Fix the dominator tree, if it is available.  */
   if (dom_info_available_p (CDI_DOMINATORS))
     {
-      VEC (basic_block, heap) *bbs_to_fix_dom;
+      vec<basic_block> bbs_to_fix_dom;
 
       set_immediate_dominator (CDI_DOMINATORS, bb1, bb0);
       set_immediate_dominator (CDI_DOMINATORS, bb2, bb0);
@@ -1318,14 +1330,14 @@ gen_inbound_check (gimple swtch, struct switch_conv_info *info)
        /* If bbD was the immediate dominator ...  */
        set_immediate_dominator (CDI_DOMINATORS, bbf, bb0);
 
-      bbs_to_fix_dom = VEC_alloc (basic_block, heap, 4);
-      VEC_quick_push (basic_block, bbs_to_fix_dom, bb0);
-      VEC_quick_push (basic_block, bbs_to_fix_dom, bb1);
-      VEC_quick_push (basic_block, bbs_to_fix_dom, bb2);
-      VEC_quick_push (basic_block, bbs_to_fix_dom, bbf);
+      bbs_to_fix_dom.create (4);
+      bbs_to_fix_dom.quick_push (bb0);
+      bbs_to_fix_dom.quick_push (bb1);
+      bbs_to_fix_dom.quick_push (bb2);
+      bbs_to_fix_dom.quick_push (bbf);
 
       iterate_fix_dominators (CDI_DOMINATORS, bbs_to_fix_dom, true);
-      VEC_free (basic_block, heap, bbs_to_fix_dom);
+      bbs_to_fix_dom.release ();
     }
 }
 
@@ -1336,12 +1348,18 @@ gen_inbound_check (gimple swtch, struct switch_conv_info *info)
    conversion failed.  */
 
 static const char *
-process_switch (gimple swtch)
+process_switch (gswitch *swtch)
 {
   struct switch_conv_info info;
 
-  /* Degenerate case with only a default label should never happen.  */
-  gcc_checking_assert (gimple_switch_num_labels (swtch) > 1);
+  /* Group case labels so that we get the right results from the heuristics
+     that decide on the code generation approach for this switch.  */
+  group_case_labels_stmt (swtch);
+
+  /* If this switch is now a degenerate case with only a default label,
+     there is nothing left for us to do.   */
+  if (gimple_switch_num_labels (swtch) < 2)
+    return "switch is a degenerate case";
 
   collect_switch_conv_info (swtch, &info);
 
@@ -1355,12 +1373,15 @@ process_switch (gimple swtch)
   if (info.uniq <= MAX_CASE_BIT_TESTS)
     {
       if (expand_switch_using_bit_tests_p (info.range_size,
-                                          info.uniq, info.count))
+                                          info.uniq, info.count,
+                                          optimize_bb_for_speed_p
+                                            (gimple_bb (swtch))))
        {
          if (dump_file)
            fputs ("  expanding as bit test is preferable\n", dump_file);
-         emit_case_bit_tests (swtch, info.index_expr,
-                              info.range_min, info.range_size);
+         emit_case_bit_tests (swtch, info.index_expr, info.range_min,
+                              info.range_size, info.range_max);
+         loops_state_set (LOOPS_NEED_FIXUP);
          return NULL;
        }
 
@@ -1397,7 +1418,7 @@ process_switch (gimple swtch)
      transformation.  */
 
   create_temp_arrays (&info);
-  gather_default_values (gimple_switch_label (swtch, 0), &info);
+  gather_default_values (gimple_switch_default_label (swtch), &info);
   build_constructors (swtch, &info);
 
   build_arrays (swtch, &info); /* Build the static arrays and assignments.   */
@@ -1411,12 +1432,40 @@ process_switch (gimple swtch)
 /* The main function of the pass scans statements for switches and invokes
    process_switch on them.  */
 
-static unsigned int
-do_switchconv (void)
+namespace {
+
+const pass_data pass_data_convert_switch =
+{
+  GIMPLE_PASS, /* type */
+  "switchconv", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  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_flags_finish */
+};
+
+class pass_convert_switch : public gimple_opt_pass
+{
+public:
+  pass_convert_switch (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_convert_switch, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *) { return flag_tree_switch_conversion != 0; }
+  virtual unsigned int execute (function *);
+
+}; // class pass_convert_switch
+
+unsigned int
+pass_convert_switch::execute (function *fun)
 {
   basic_block bb;
 
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, fun)
   {
     const char *failure_reason;
     gimple stmt = last_stmt (bb);
@@ -1433,7 +1482,7 @@ do_switchconv (void)
            putc ('\n', dump_file);
          }
 
-       failure_reason = process_switch (stmt);
+       failure_reason = process_switch (as_a <gswitch *> (stmt));
        if (! failure_reason)
          {
            if (dump_file)
@@ -1462,32 +1511,10 @@ do_switchconv (void)
   return 0;
 }
 
-/* The pass gate. */
+} // anon namespace
 
-static bool
-switchconv_gate (void)
+gimple_opt_pass *
+make_pass_convert_switch (gcc::context *ctxt)
 {
-  return flag_tree_switch_conversion != 0;
+  return new pass_convert_switch (ctxt);
 }
-
-struct gimple_opt_pass pass_convert_switch =
-{
- {
-  GIMPLE_PASS,
-  "switchconv",                                /* name */
-  switchconv_gate,                     /* gate */
-  do_switchconv,                       /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  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_ggc_collect | TODO_verify_ssa
-  | TODO_verify_stmts
-  | TODO_verify_flow                   /* todo_flags_finish */
- }
-};