On Wed, 2013-11-06 at 22:32 -0700, Jeff Law wrote:
> [ Just a note, of this reply is meant for Michael and other parts for 
> David, hopefully the audience is clear from the context. ]
> 
> On 11/06/13 21:56, David Malcolm wrote:
> > On Wed, 2013-11-06 at 16:32 +0100, Michael Matz wrote:
> >> Hi,
> >>
> >> On Tue, 5 Nov 2013, David Malcolm wrote:
> >>
> >>> Here's a followup patch which ensures that every gimple code has its own
> >>> subclass, by adding empty subclasses derived from the GSS_-based
> >>> subclasses as appropriate (I don't bother for gimple codes that already
> >>> have their own subclass due to having their own GSS layout).  I also
> >>> copied the comments from gimple.def into gimple.h, so that Doxygen picks
> >>> up on the descriptions and uses them to describe each subclass.
> >>
> >> I don't like that.  The empty classes are just useless, they imply a
> >> structure that isn't really there, some of the separate gimple codes are
> >> basically selectors of specific subtypes of a generic concept, without
> >> additional data or methods; creating a type for those is confusing.
> >
> > A type system does more than just express memory layouts:
> > * it permits the proof of absence of certain bugs
> Right.  As you have probably surmised, this is the single biggest thing 
> we get from this work in my mind.  We use the type system to ensure a 
> certain class of bugs simply won't get through the compilation phase.
> 
> That's a significant and important change from where we are now.  Right 
> now we have no way of knowing that at compile time.  Instead we rely 
> upon an insane set of macros to check this kind of invariant at run 
> time.  Note carefully just because we don't hit a checking failure 
> doesn't mean the code is safe.  It just means we haven't found a set of 
> preconditions necessary to trip the problem at runtime.  Obviously in 
> some (many), where may be no such way to trigger the failure, but 
> there's no way to prove it.
> 
> Don't get me wrong the checking macros, when they were introduced were a 
> godsend.  But they're papering over a fundamental problems in GCC's 
> internal representations.
> 
> I think it's hard to overestimate the value we get by moving this stuff 
> into compile-time type checking.
> 
> 
> > I can post a followup patch that makes use of each of these, if it will
> > help.
> I wouldn't mind seeing a small example proof of concept posted to help 
> those who don't see where this is going understand the goal.  I would 
> recommend against posting another large patch for inclusion at this time.
Attached is a proof-of-concept patch which uses the
gimple_statement_switch subclass (as a "gimple_switch" typedef).  This
is one of the subclasses that the earlier patch added, which has no new
fields, but which carries the invariant that, if non-NULL,
   gimple_code (gs) == GIMPLE_SWITCH.

The patch adds compile-time type-checking for places where switch
statements are handled.  For example, in tree-vrp.c's switch_update:
 typedef struct {
-  gimple stmt;
+  gimple_switch stmt;
   tree vec;
 } switch_update;

we can capture the fact that the statements have code GIMPLE_SWITCH.

I was able to make 7 of the 9 gimple_switch_* accessors accept a
gimple_switch rather than a gimple, hence adding compile-time typesafety
for these.  We could do all of them, but doing the remaining two would
enlarge the patch (I did the ones where the site of the downcast already
has enclosing braces handy to scope the subclass pointer).

I kept the run-time checking in those accessors, though arguably they're
redundant.

I deliberately used a C style for the downcast from gimple to a more
specialized type, eschewing the dyn_cast<> template, though IMHO the
latter is a better style.   Perhaps a specialized dyncast method to
gimple would be more acceptable e.g.:

struct GTY((etc)) gimple statement_base {
   [...]

   gimple_switch is_switch () const
   {
        if (gimple_code (this) == GIMPLE_SWITCH)
           return (gimple_switch)this;
        else
           return NULL;
   }
};

allowing us to spell a dynamic cast like this:
   if (gimple_switch switch_stmt = stmt->is_switch ())
     {
        /* do typesafe stuff with switch_stmt */
     }


commit b9e2375b4250428cc20e83c9be9be80afbfcb388
Author: David Malcolm <dmalc...@redhat.com>
Date:   Thu Nov 7 21:32:15 2013 -0500

    Use gimple_switch in various places

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index fb05ce7..cc2d4d7 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -2221,7 +2221,7 @@ expand_gimple_stmt_1 (gimple stmt)
     case GIMPLE_PREDICT:
       break;
     case GIMPLE_SWITCH:
-      expand_case (stmt);
+      expand_case ((gimple_switch)stmt);
       break;
     case GIMPLE_ASM:
       expand_asm_stmt (stmt);
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 5a5cfbb..a72ebb4 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -69,6 +69,9 @@ typedef struct gimple_stmt_iterator_d gimple_stmt_iterator;
 /* FWIW I'd rather simply have the class be called "gimple_call", and
    make the pointerness be explicit rather than implicit.  */
 typedef struct gimple_statement_call *gimple_call;
+typedef const struct gimple_statement_call *const_gimple_call;
+typedef struct gimple_statement_switch *gimple_switch;
+typedef const struct gimple_statement_switch *const_gimple_switch;
 union section;
 typedef union section section;
 struct gcc_options;
diff --git a/gcc/expr.h b/gcc/expr.h
index 56f504a..f5bed84 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -734,7 +734,7 @@ rtx get_personality_function (tree);
 /* In stmt.c */
 
 /* Expand a GIMPLE_SWITCH statement.  */
-extern void expand_case (gimple);
+extern void expand_case (gimple_switch);
 
 /* Like expand_case but special-case for SJLJ exception dispatching.  */
 extern void expand_sjlj_dispatch_table (rtx, vec<tree> );
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index b9bbdc7..690b43e 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -763,7 +763,7 @@ dump_gimple_call (pretty_printer *buffer, gimple gs, int spc, int flags)
    pp_gimple_stmt_1.  */
 
 static void
-dump_gimple_switch (pretty_printer *buffer, gimple gs, int spc, int flags)
+dump_gimple_switch (pretty_printer *buffer, gimple_switch gs, int spc, int flags)
 {
   unsigned int i;
 
@@ -2100,7 +2100,7 @@ pp_gimple_stmt_1 (pretty_printer *buffer, gimple gs, int spc, int flags)
       break;
 
     case GIMPLE_SWITCH:
-      dump_gimple_switch (buffer, gs, spc, flags);
+      dump_gimple_switch (buffer, (gimple_switch)gs, spc, flags);
       break;
 
     case GIMPLE_TRY:
diff --git a/gcc/gimple.c b/gcc/gimple.c
index a128582..f182d0e 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -822,13 +822,14 @@ gimple_build_resx (int region)
    NLABELS is the number of labels in the switch excluding the default.
    DEFAULT_LABEL is the default label for the switch statement.  */
 
-gimple
+gimple_switch
 gimple_build_switch_nlabels (unsigned nlabels, tree index, tree default_label)
 {
   /* nlabels + 1 default label + 1 index.  */
   gcc_checking_assert (default_label);
-  gimple p = gimple_build_with_ops (GIMPLE_SWITCH, ERROR_MARK,
-				    1 + 1 + nlabels);
+  gimple_switch p =
+    (gimple_switch)gimple_build_with_ops (GIMPLE_SWITCH, ERROR_MARK,
+					  1 + 1 + nlabels);
   gimple_switch_set_index (p, index);
   gimple_switch_set_default_label (p, default_label);
   return p;
@@ -840,12 +841,12 @@ gimple_build_switch_nlabels (unsigned nlabels, tree index, tree default_label)
    DEFAULT_LABEL is the default label
    ARGS is a vector of labels excluding the default.  */
 
-gimple
+gimple_switch
 gimple_build_switch (tree index, tree default_label, vec<tree> args)
 {
   unsigned i, nlabels = args.length ();
 
-  gimple p = gimple_build_switch_nlabels (nlabels, index, default_label);
+  gimple_switch p = gimple_build_switch_nlabels (nlabels, index, default_label);
 
   /* Copy the labels from the vector to the switch statement.  */
   for (i = 0; i < nlabels; i++)
diff --git a/gcc/gimple.h b/gcc/gimple.h
index cd9f89f..63827a6 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1538,8 +1538,8 @@ gimple_statement_try *gimple_build_try (gimple_seq, gimple_seq,
 gimple gimple_build_wce (gimple_seq);
 gimple gimple_build_resx (int);
 gimple gimple_build_eh_dispatch (int);
-gimple gimple_build_switch_nlabels (unsigned, tree, tree);
-gimple gimple_build_switch (tree, tree, vec<tree> );
+gimple_switch gimple_build_switch_nlabels (unsigned, tree, tree);
+gimple_switch gimple_build_switch (tree, tree, vec<tree> );
 gimple gimple_build_omp_parallel (gimple_seq, tree, tree, tree);
 gimple gimple_build_omp_task (gimple_seq, tree, tree, tree, tree, tree, tree);
 gimple gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq);
@@ -4592,7 +4592,7 @@ gimple_eh_dispatch_set_region (gimple gs, int region)
 /* Return the number of labels associated with the switch statement GS.  */
 
 static inline unsigned
-gimple_switch_num_labels (const_gimple gs)
+gimple_switch_num_labels (const_gimple_switch gs)
 {
   unsigned num_ops;
   GIMPLE_CHECK (gs, GIMPLE_SWITCH);
@@ -4605,7 +4605,7 @@ gimple_switch_num_labels (const_gimple gs)
 /* Set NLABELS to be the number of labels for the switch statement GS.  */
 
 static inline void
-gimple_switch_set_num_labels (gimple g, unsigned nlabels)
+gimple_switch_set_num_labels (gimple_switch g, unsigned nlabels)
 {
   GIMPLE_CHECK (g, GIMPLE_SWITCH);
   gimple_set_num_ops (g, nlabels + 1);
@@ -4635,7 +4635,7 @@ gimple_switch_index_ptr (const_gimple gs)
 /* Set INDEX to be the index variable for switch statement GS.  */
 
 static inline void
-gimple_switch_set_index (gimple gs, tree index)
+gimple_switch_set_index (gimple_switch gs, tree index)
 {
   GIMPLE_CHECK (gs, GIMPLE_SWITCH);
   gcc_gimple_checking_assert (SSA_VAR_P (index) || CONSTANT_CLASS_P (index));
@@ -4647,7 +4647,7 @@ gimple_switch_set_index (gimple gs, tree index)
    labels in a switch statement.  */
 
 static inline tree
-gimple_switch_label (const_gimple gs, unsigned index)
+gimple_switch_label (const_gimple_switch gs, unsigned index)
 {
   GIMPLE_CHECK (gs, GIMPLE_SWITCH);
   gcc_gimple_checking_assert (gimple_num_ops (gs) > index + 1);
@@ -4657,7 +4657,7 @@ gimple_switch_label (const_gimple gs, unsigned index)
 /* Set the label number INDEX to LABEL.  0 is always the default label.  */
 
 static inline void
-gimple_switch_set_label (gimple gs, unsigned index, tree label)
+gimple_switch_set_label (gimple_switch gs, unsigned index, tree label)
 {
   GIMPLE_CHECK (gs, GIMPLE_SWITCH);
   gcc_gimple_checking_assert (gimple_num_ops (gs) > index + 1
@@ -4669,7 +4669,7 @@ gimple_switch_set_label (gimple gs, unsigned index, tree label)
 /* Return the default label for a switch statement.  */
 
 static inline tree
-gimple_switch_default_label (const_gimple gs)
+gimple_switch_default_label (const_gimple_switch gs)
 {
   tree label = gimple_switch_label (gs, 0);
   gcc_checking_assert (!CASE_LOW (label) && !CASE_HIGH (label));
@@ -4679,7 +4679,7 @@ gimple_switch_default_label (const_gimple gs)
 /* Set the default label for a switch statement.  */
 
 static inline void
-gimple_switch_set_default_label (gimple gs, tree label)
+gimple_switch_set_default_label (gimple_switch gs, tree label)
 {
   gcc_checking_assert (!CASE_LOW (label) && !CASE_HIGH (label));
   gimple_switch_set_label (gs, 0, label);
diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
index 83bd479..8958f1f 100644
--- a/gcc/ipa-inline-analysis.c
+++ b/gcc/ipa-inline-analysis.c
@@ -1765,7 +1765,7 @@ set_switch_stmt_execution_predicate (struct ipa_node_params *info,
 				     struct inline_summary *summary,
 				     basic_block bb)
 {
-  gimple last;
+  gimple lastg;
   tree op;
   int index;
   struct agg_position_info aggpos;
@@ -1774,9 +1774,10 @@ set_switch_stmt_execution_predicate (struct ipa_node_params *info,
   size_t n;
   size_t case_idx;
 
-  last = last_stmt (bb);
-  if (!last || gimple_code (last) != GIMPLE_SWITCH)
+  lastg = last_stmt (bb);
+  if (!lastg || gimple_code (lastg) != GIMPLE_SWITCH)
     return;
+  gimple_switch last = (gimple_switch)lastg;
   op = gimple_switch_index (last);
   if (!unmodified_parm_or_parm_agg_item (info, last, op, &index, &aggpos))
     return;
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 3b7882d..4ef1f4c 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -10324,10 +10324,11 @@ diagnose_sb_2 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
 
     case GIMPLE_SWITCH:
       {
+	gimple_switch switch_stmt = (gimple_switch)stmt;
 	unsigned int i;
-	for (i = 0; i < gimple_switch_num_labels (stmt); ++i)
+	for (i = 0; i < gimple_switch_num_labels (switch_stmt); ++i)
 	  {
-	    tree lab = CASE_LABEL (gimple_switch_label (stmt, i));
+	    tree lab = CASE_LABEL (gimple_switch_label (switch_stmt, i));
 	    n = splay_tree_lookup (all_labels, (splay_tree_key) lab);
 	    if (n && diagnose_sb_0 (gsi_p, context, (gimple) n->value))
 	      break;
diff --git a/gcc/stmt.c b/gcc/stmt.c
index b3fd255..1d7298b 100644
--- a/gcc/stmt.c
+++ b/gcc/stmt.c
@@ -2010,7 +2010,7 @@ reset_out_edges_aux (basic_block bb)
    STMT. Record this information in the aux field of the edge.  */
 
 static inline void
-compute_cases_per_edge (gimple stmt)
+compute_cases_per_edge (gimple_switch stmt)
 {
   basic_block bb = gimple_bb (stmt);
   reset_out_edges_aux (bb);
@@ -2032,7 +2032,7 @@ compute_cases_per_edge (gimple stmt)
    Generate the code to test it and jump to the right place.  */
 
 void
-expand_case (gimple stmt)
+expand_case (gimple_switch stmt)
 {
   tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE;
   rtx default_label = NULL_RTX;
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 8d82342..3cbb232 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -141,7 +141,7 @@ static void factor_computed_gotos (void);
 static void make_edges (void);
 static void assign_discriminators (void);
 static void make_cond_expr_edges (basic_block);
-static void make_gimple_switch_edges (basic_block);
+static void make_gimple_switch_edges (gimple_switch, basic_block);
 static void make_goto_expr_edges (basic_block);
 static void make_gimple_asm_edges (basic_block);
 static edge gimple_redirect_edge_and_branch (edge, basic_block);
@@ -161,8 +161,8 @@ static bool gimple_can_merge_blocks_p (basic_block, basic_block);
 static void remove_bb (basic_block);
 static edge find_taken_edge_computed_goto (basic_block, tree);
 static edge find_taken_edge_cond_expr (basic_block, tree);
-static edge find_taken_edge_switch_expr (basic_block, tree);
-static tree find_case_label_for_value (gimple, tree);
+static edge find_taken_edge_switch_expr (gimple_switch, basic_block, tree);
+static tree find_case_label_for_value (gimple_switch, tree);
 
 void
 init_empty_tree_cfg_for_function (struct function *fn)
@@ -644,7 +644,7 @@ make_edges (void)
 	      fallthru = false;
 	      break;
 	    case GIMPLE_SWITCH:
-	      make_gimple_switch_edges (bb);
+	      make_gimple_switch_edges ((gimple_switch)last, bb);
 	      fallthru = false;
 	      break;
 	    case GIMPLE_RESX:
@@ -892,7 +892,7 @@ end_recording_case_labels (void)
 	{
 	  gimple stmt = last_stmt (bb);
 	  if (stmt && gimple_code (stmt) == GIMPLE_SWITCH)
-	    group_case_labels_stmt (stmt);
+	    group_case_labels_stmt ((gimple_switch)stmt);
 	}
     }
   BITMAP_FREE (touched_switch_bbs);
@@ -904,7 +904,7 @@ end_recording_case_labels (void)
    Otherwise return NULL.  */
 
 static tree
-get_cases_for_edge (edge e, gimple t)
+get_cases_for_edge (edge e, gimple_switch t)
 {
   void **slot;
   size_t i, n;
@@ -943,9 +943,8 @@ get_cases_for_edge (edge e, gimple t)
 /* Create the edges for a GIMPLE_SWITCH starting at block BB.  */
 
 static void
-make_gimple_switch_edges (basic_block bb)
+make_gimple_switch_edges (gimple_switch entry, basic_block bb)
 {
-  gimple entry = last_stmt (bb);
   size_t i, n;
 
   n = gimple_switch_num_labels (entry);
@@ -1238,12 +1237,13 @@ cleanup_dead_labels (void)
 
 	case GIMPLE_SWITCH:
 	  {
-	    size_t i, n = gimple_switch_num_labels (stmt);
+	    gimple_switch switch_stmt = (gimple_switch)stmt;
+	    size_t i, n = gimple_switch_num_labels (switch_stmt);
 
 	    /* Replace all destination labels.  */
 	    for (i = 0; i < n; ++i)
 	      {
-		tree case_label = gimple_switch_label (stmt, i);
+		tree case_label = gimple_switch_label (switch_stmt, i);
 		label = CASE_LABEL (case_label);
 		new_label = main_block_label (label);
 		if (new_label != label)
@@ -1340,7 +1340,7 @@ cleanup_dead_labels (void)
    Eg. three separate entries 1: 2: 3: become one entry 1..3:  */
 
 void
-group_case_labels_stmt (gimple stmt)
+group_case_labels_stmt (gimple_switch stmt)
 {
   int old_size = gimple_switch_num_labels (stmt);
   int i, j, new_size = old_size;
@@ -1428,7 +1428,7 @@ group_case_labels (void)
     {
       gimple stmt = last_stmt (bb);
       if (stmt && gimple_code (stmt) == GIMPLE_SWITCH)
-	group_case_labels_stmt (stmt);
+	group_case_labels_stmt ((gimple_switch)stmt);
     }
 }
 
@@ -1895,7 +1895,7 @@ find_taken_edge (basic_block bb, tree val)
     return find_taken_edge_cond_expr (bb, val);
 
   if (gimple_code (stmt) == GIMPLE_SWITCH)
-    return find_taken_edge_switch_expr (bb, val);
+    return find_taken_edge_switch_expr ((gimple_switch)stmt, bb, val);
 
   if (computed_goto_p (stmt))
     {
@@ -1954,14 +1954,13 @@ find_taken_edge_cond_expr (basic_block bb, tree val)
    NULL if any edge may be taken.  */
 
 static edge
-find_taken_edge_switch_expr (basic_block bb, tree val)
+find_taken_edge_switch_expr (gimple_switch switch_stmt, basic_block bb,
+			     tree val)
 {
   basic_block dest_bb;
   edge e;
-  gimple switch_stmt;
   tree taken_case;
 
-  switch_stmt = last_stmt (bb);
   taken_case = find_case_label_for_value (switch_stmt, val);
   dest_bb = label_to_block (CASE_LABEL (taken_case));
 
@@ -1976,7 +1975,7 @@ find_taken_edge_switch_expr (basic_block bb, tree val)
    sorted: We can do a binary search for a case matching VAL.  */
 
 static tree
-find_case_label_for_value (gimple switch_stmt, tree val)
+find_case_label_for_value (gimple_switch switch_stmt, tree val)
 {
   size_t low, high, n = gimple_switch_num_labels (switch_stmt);
   tree default_case = gimple_switch_default_label (switch_stmt);
@@ -4089,7 +4088,7 @@ verify_gimple_goto (gimple stmt)
    is a problem, otherwise false.  */
 
 static bool
-verify_gimple_switch (gimple stmt)
+verify_gimple_switch (gimple_switch stmt)
 {
   unsigned int i, n;
   tree elt, prev_upper_bound = NULL_TREE;
@@ -4270,7 +4269,7 @@ verify_gimple_stmt (gimple stmt)
       return verify_gimple_goto (stmt);
 
     case GIMPLE_SWITCH:
-      return verify_gimple_switch (stmt);
+      return verify_gimple_switch ((gimple_switch)stmt);
 
     case GIMPLE_RETURN:
       return verify_gimple_return (stmt);
@@ -5000,26 +4999,27 @@ gimple_verify_flow_info (void)
 
 	case GIMPLE_SWITCH:
 	  {
+	    gimple_switch switch_stmt = (gimple_switch)stmt;
 	    tree prev;
 	    edge e;
 	    size_t i, n;
 
-	    n = gimple_switch_num_labels (stmt);
+	    n = gimple_switch_num_labels (switch_stmt);
 
 	    /* Mark all the destination basic blocks.  */
 	    for (i = 0; i < n; ++i)
 	      {
-		tree lab = CASE_LABEL (gimple_switch_label (stmt, i));
+		tree lab = CASE_LABEL (gimple_switch_label (switch_stmt, i));
 		basic_block label_bb = label_to_block (lab);
 		gcc_assert (!label_bb->aux || label_bb->aux == (void *)1);
 		label_bb->aux = (void *)1;
 	      }
 
 	    /* Verify that the case labels are sorted.  */
-	    prev = gimple_switch_label (stmt, 0);
+	    prev = gimple_switch_label (switch_stmt, 0);
 	    for (i = 1; i < n; ++i)
 	      {
-		tree c = gimple_switch_label (stmt, i);
+		tree c = gimple_switch_label (switch_stmt, i);
 		if (!CASE_LOW (c))
 		  {
 		    error ("found default case not at the start of "
@@ -5065,7 +5065,7 @@ gimple_verify_flow_info (void)
 	    /* Check that we have all of them.  */
 	    for (i = 0; i < n; ++i)
 	      {
-		tree lab = CASE_LABEL (gimple_switch_label (stmt, i));
+		tree lab = CASE_LABEL (gimple_switch_label (switch_stmt, i));
 		basic_block label_bb = label_to_block (lab);
 
 		if (label_bb->aux != (void *)2)
@@ -5253,8 +5253,9 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
 
     case GIMPLE_SWITCH:
       {
+	gimple_switch switch_stmt = (gimple_switch)stmt;
 	tree label = gimple_block_label (dest);
-        tree cases = get_cases_for_edge (e, stmt);
+        tree cases = get_cases_for_edge (e, switch_stmt);
 
 	/* If we have a list of cases associated with E, then use it
 	   as it's a lot faster than walking the entire case vector.  */
@@ -5275,7 +5276,7 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
 	       to move all the cases associated with E to E2.  */
 	    if (e2)
 	      {
-		tree cases2 = get_cases_for_edge (e2, stmt);
+		tree cases2 = get_cases_for_edge (e2, switch_stmt);
 
 		CASE_CHAIN (last) = CASE_CHAIN (cases2);
 		CASE_CHAIN (cases2) = first;
@@ -5284,11 +5285,11 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
 	  }
 	else
 	  {
-	    size_t i, n = gimple_switch_num_labels (stmt);
+	    size_t i, n = gimple_switch_num_labels (switch_stmt);
 
 	    for (i = 0; i < n; i++)
 	      {
-		tree elt = gimple_switch_label (stmt, i);
+		tree elt = gimple_switch_label (switch_stmt, i);
 		if (label_to_block (CASE_LABEL (elt)) == e->dest)
 		  CASE_LABEL (elt) = label;
 	      }
diff --git a/gcc/tree-cfg.h b/gcc/tree-cfg.h
index d6a5d8f..72e2637 100644
--- a/gcc/tree-cfg.h
+++ b/gcc/tree-cfg.h
@@ -33,7 +33,7 @@ extern basic_block label_to_block_fn (struct function *, tree);
 #define label_to_block(t) (label_to_block_fn (cfun, t))
 extern void make_abnormal_goto_edges (basic_block, bool);
 extern void cleanup_dead_labels (void);
-extern void group_case_labels_stmt (gimple);
+extern void group_case_labels_stmt (gimple_switch);
 extern void group_case_labels (void);
 extern void replace_uses_by (tree, tree);
 extern basic_block single_noncomplex_succ (basic_block bb);
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index c83229f..d62aa0a 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -704,7 +704,7 @@ maybe_record_in_goto_queue (struct leh_state *state, gimple stmt)
    of the labels will leave outer GIMPLE_TRY_FINALLY nodes. Verify this.  */
 
 static void
-verify_norecord_switch_expr (struct leh_state *state, gimple switch_expr)
+verify_norecord_switch_expr (struct leh_state *state, gimple_switch switch_expr)
 {
   struct leh_tf_state *tf = state->tf;
   size_t i, n;
@@ -2048,7 +2048,7 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
       break;
 
     case GIMPLE_SWITCH:
-      verify_norecord_switch_expr (state, stmt);
+      verify_norecord_switch_expr (state, (gimple_switch)stmt);
       break;
 
     case GIMPLE_TRY:
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index e4c80a7..bd74949 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -3727,15 +3727,18 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
       break;
 
     case GIMPLE_SWITCH:
-      /* Take into account cost of the switch + guess 2 conditional jumps for
-         each case label.
-
-	 TODO: once the switch expansion logic is sufficiently separated, we can
-	 do better job on estimating cost of the switch.  */
-      if (weights->time_based)
-        cost = floor_log2 (gimple_switch_num_labels (stmt)) * 2;
-      else
-        cost = gimple_switch_num_labels (stmt) * 2;
+      {
+	gimple_switch switch_stmt = (gimple_switch)stmt;
+	/* Take into account cost of the switch + guess 2 conditional jumps for
+	   each case label.
+
+	   TODO: once the switch expansion logic is sufficiently separated, we can
+	   do better job on estimating cost of the switch.  */
+	if (weights->time_based)
+	  cost = floor_log2 (gimple_switch_num_labels (switch_stmt)) * 2;
+	else
+	  cost = gimple_switch_num_labels (switch_stmt) * 2;
+      }
       break;
 
     case GIMPLE_CALL:
diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
index 353ce24..c0cd9ea 100644
--- a/gcc/tree-loop-distribution.c
+++ b/gcc/tree-loop-distribution.c
@@ -679,8 +679,9 @@ generate_loops_for_partition (struct loop *loop, partition_t partition,
 		}
 	      else if (gimple_code (stmt) == GIMPLE_SWITCH)
 		{
+		  gimple_switch switch_stmt = (gimple_switch)stmt;
 		  gimple_switch_set_index
-		      (stmt, CASE_LOW (gimple_switch_label (stmt, 1)));
+		      (switch_stmt, CASE_LOW (gimple_switch_label (switch_stmt, 1)));
 		  update_stmt (stmt);
 		}
 	      else
diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
index 211bfcf..e563366 100644
--- a/gcc/tree-ssa-dom.c
+++ b/gcc/tree-ssa-dom.c
@@ -1755,19 +1755,20 @@ record_edge_info (basic_block bb)
 
       if (gimple_code (stmt) == GIMPLE_SWITCH)
 	{
+	  gimple_switch switch_stmt = (gimple_switch)stmt;
 	  tree index = gimple_switch_index (stmt);
 
 	  if (TREE_CODE (index) == SSA_NAME)
 	    {
 	      int i;
-              int n_labels = gimple_switch_num_labels (stmt);
+              int n_labels = gimple_switch_num_labels (switch_stmt);
 	      tree *info = XCNEWVEC (tree, last_basic_block);
 	      edge e;
 	      edge_iterator ei;
 
 	      for (i = 0; i < n_labels; i++)
 		{
-		  tree label = gimple_switch_label (stmt, i);
+		  tree label = gimple_switch_label (switch_stmt, i);
 		  basic_block target_bb = label_to_block (CASE_LABEL (label));
 		  if (CASE_HIGH (label)
 		      || !CASE_LOW (label)
diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
index 6ad45c9..116ab27 100644
--- a/gcc/tree-ssa-forwprop.c
+++ b/gcc/tree-ssa-forwprop.c
@@ -1272,7 +1272,7 @@ simplify_not_neg_expr (gimple_stmt_iterator *gsi_p)
    have values outside the range of the new type.  */
 
 static void
-simplify_gimple_switch_label_vec (gimple stmt, tree index_type)
+simplify_gimple_switch_label_vec (gimple_switch stmt, tree index_type)
 {
   unsigned int branch_num = gimple_switch_num_labels (stmt);
   vec<tree> labels;
@@ -1345,7 +1345,7 @@ simplify_gimple_switch_label_vec (gimple stmt, tree index_type)
    the condition which we may be able to optimize better.  */
 
 static bool
-simplify_gimple_switch (gimple stmt)
+simplify_gimple_switch (gimple_switch stmt)
 {
   tree cond = gimple_switch_index (stmt);
   tree def, to, ti;
@@ -3502,7 +3502,7 @@ ssa_forward_propagate_and_combine (void)
 	      }
 
 	    case GIMPLE_SWITCH:
-	      changed = simplify_gimple_switch (stmt);
+	      changed = simplify_gimple_switch ((gimple_switch)stmt);
 	      break;
 
 	    case GIMPLE_COND:
diff --git a/gcc/tree-ssa-uncprop.c b/gcc/tree-ssa-uncprop.c
index 71c1f5d..6a32b26 100644
--- a/gcc/tree-ssa-uncprop.c
+++ b/gcc/tree-ssa-uncprop.c
@@ -166,12 +166,13 @@ associate_equivalences_with_edges (void)
 	 target block creates an equivalence.  */
       else if (gimple_code (stmt) == GIMPLE_SWITCH)
 	{
-	  tree cond = gimple_switch_index (stmt);
+	  gimple_switch switch_stmt = (gimple_switch)stmt;
+	  tree cond = gimple_switch_index (switch_stmt);
 
 	  if (TREE_CODE (cond) == SSA_NAME
 	      && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (cond))
 	    {
-	      int i, n_labels = gimple_switch_num_labels (stmt);
+	      int i, n_labels = gimple_switch_num_labels (switch_stmt);
 	      tree *info = XCNEWVEC (tree, last_basic_block);
 
 	      /* Walk over the case label vector.  Record blocks
@@ -179,7 +180,7 @@ associate_equivalences_with_edges (void)
 		 a single value.  */
 	      for (i = 0; i < n_labels; i++)
 		{
-		  tree label = gimple_switch_label (stmt, i);
+		  tree label = gimple_switch_label (switch_stmt, i);
 		  basic_block bb = label_to_block (CASE_LABEL (label));
 
 		  if (CASE_HIGH (label)
diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c
index 46b9efe..4adb758 100644
--- a/gcc/tree-switch-conversion.c
+++ b/gcc/tree-switch-conversion.c
@@ -292,7 +292,7 @@ case_bit_test_cmp (const void *p1, const void *p2)
     node targets.  */
 
 static void
-emit_case_bit_tests (gimple swtch, tree index_expr,
+emit_case_bit_tests (gimple_switch swtch, tree index_expr,
 		     tree minval, tree range)
 {
   struct case_bit_test test[MAX_CASE_BIT_TESTS];
@@ -604,7 +604,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 (gimple_switch swtch, struct switch_conv_info *info)
 {
   unsigned int branch_num = gimple_switch_num_labels (swtch);
   tree min_case, max_case;
@@ -848,7 +848,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 (gimple_switch swtch, struct switch_conv_info *info)
 {
   unsigned i, branch_num = gimple_switch_num_labels (swtch);
   tree pos = info->range_min;
@@ -940,7 +940,7 @@ constructor_contains_same_values_p (vec<constructor_elt, va_gc> *vec)
    all the constants.  */
 
 static tree
-array_value_type (gimple swtch, tree type, int num,
+array_value_type (gimple_switch swtch, tree type, int num,
 		  struct switch_conv_info *info)
 {
   unsigned int i, len = vec_safe_length (info->constructors[num]);
@@ -1017,7 +1017,7 @@ 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,
+build_one_array (gimple_switch swtch, int num, tree arr_index_type, gimple phi,
 		 tree tidx, struct switch_conv_info *info)
 {
   tree name, cst;
@@ -1083,7 +1083,7 @@ 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 (gimple_switch swtch, struct switch_conv_info *info)
 {
   tree arr_index_type;
   tree tidx, sub, utype;
@@ -1204,7 +1204,7 @@ 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 (gimple_switch swtch, struct switch_conv_info *info)
 {
   tree label_decl1 = create_artificial_label (UNKNOWN_LOCATION);
   tree label_decl2 = create_artificial_label (UNKNOWN_LOCATION);
@@ -1324,7 +1324,7 @@ gen_inbound_check (gimple swtch, struct switch_conv_info *info)
    conversion failed.  */
 
 static const char *
-process_switch (gimple swtch)
+process_switch (gimple_switch swtch)
 {
   struct switch_conv_info info;
 
@@ -1429,7 +1429,7 @@ do_switchconv (void)
 	    putc ('\n', dump_file);
 	  }
 
-	failure_reason = process_switch (stmt);
+	failure_reason = process_switch ((gimple_switch)stmt);
 	if (! failure_reason)
 	  {
 	    if (dump_file)
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index d3a07f3..bd470f9 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -158,7 +158,7 @@ static bool values_propagated;
 static int *vr_phi_edge_counts;
 
 typedef struct {
-  gimple stmt;
+  gimple_switch stmt;
   tree vec;
 } switch_update;
 
@@ -5668,7 +5668,7 @@ compare_case_labels (const void *p1, const void *p2)
    list of assertions for the corresponding operands.  */
 
 static bool
-find_switch_asserts (basic_block bb, gimple last)
+find_switch_asserts (basic_block bb, gimple_switch last)
 {
   bool need_assert;
   gimple_stmt_iterator bsi;
@@ -5839,7 +5839,7 @@ find_assert_locations_1 (basic_block bb, sbitmap live)
   if (last
       && gimple_code (last) == GIMPLE_SWITCH
       && !ZERO_SSA_OPERANDS (last, SSA_OP_USE))
-    need_assert |= find_switch_asserts (bb, last);
+    need_assert |= find_switch_asserts (bb, (gimple_switch)last);
 
   /* Traverse all the statements in BB marking used names and looking
      for statements that may infer assertions for their used operands.  */
@@ -7176,7 +7176,7 @@ vrp_visit_cond_stmt (gimple stmt, edge *taken_edge_p)
    returned. */
 
 static bool
-find_case_label_index (gimple stmt, size_t start_idx, tree val, size_t *idx)
+find_case_label_index (gimple_switch stmt, size_t start_idx, tree val, size_t *idx)
 {
   size_t n = gimple_switch_num_labels (stmt);
   size_t low, high;
@@ -7226,7 +7226,7 @@ find_case_label_index (gimple stmt, size_t start_idx, tree val, size_t *idx)
    Returns true if the default label is not needed. */
 
 static bool
-find_case_label_range (gimple stmt, tree min, tree max, size_t *min_idx,
+find_case_label_range (gimple_switch stmt, tree min, tree max, size_t *min_idx,
 		       size_t *max_idx)
 {
   size_t i, j;
@@ -7282,7 +7282,7 @@ find_case_label_range (gimple stmt, tree min, tree max, size_t *min_idx,
    Returns true if the default label is not needed.  */
 
 static bool
-find_case_label_ranges (gimple stmt, value_range_t *vr, size_t *min_idx1,
+find_case_label_ranges (gimple_switch stmt, value_range_t *vr, size_t *min_idx1,
 			size_t *max_idx1, size_t *min_idx2,
 			size_t *max_idx2)
 {
@@ -7360,7 +7360,7 @@ find_case_label_ranges (gimple stmt, value_range_t *vr, size_t *min_idx1,
    SSA_PROP_VARYING.  */
 
 static enum ssa_prop_result
-vrp_visit_switch_stmt (gimple stmt, edge *taken_edge_p)
+vrp_visit_switch_stmt (gimple_switch stmt, edge *taken_edge_p)
 {
   tree op, val;
   value_range_t *vr;
@@ -7476,7 +7476,7 @@ vrp_visit_stmt (gimple stmt, edge *taken_edge_p, tree *output_p)
   else if (gimple_code (stmt) == GIMPLE_COND)
     return vrp_visit_cond_stmt (stmt, taken_edge_p);
   else if (gimple_code (stmt) == GIMPLE_SWITCH)
-    return vrp_visit_switch_stmt (stmt, taken_edge_p);
+    return vrp_visit_switch_stmt ((gimple_switch)stmt, taken_edge_p);
 
   /* All other statements produce nothing of interest for VRP, so mark
      their outputs varying and prevent further simulation.  */
@@ -8928,7 +8928,7 @@ simplify_cond_using_ranges (gimple stmt)
    argument.  */
 
 static bool
-simplify_switch_using_ranges (gimple stmt)
+simplify_switch_using_ranges (gimple_switch stmt)
 {
   tree op = gimple_switch_index (stmt);
   value_range_t *vr;
@@ -9234,7 +9234,7 @@ simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
   else if (gimple_code (stmt) == GIMPLE_COND)
     return simplify_cond_using_ranges (stmt);
   else if (gimple_code (stmt) == GIMPLE_SWITCH)
-    return simplify_switch_using_ranges (stmt);
+    return simplify_switch_using_ranges ((gimple_switch)stmt);
 
   return false;
 }

Reply via email to