diff mbox

Add gimple subclasses for every gimple code (was Re: [PATCH 0/6] Conversion of gimple types to C++ inheritance (v3))

Message ID 1383937364.31927.66.camel@surprise
State New
Headers show

Commit Message

David Malcolm Nov. 8, 2013, 7:02 p.m. UTC
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 */
     }

Comments

Jeff Law Nov. 14, 2013, 7:13 a.m. UTC | #1
On 11/08/13 12:02, David Malcolm wrote:
>> 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.
[ ... ]

Thanks.  It's pretty much what I expected.  Obviously for other codes 
there may be a lot more changes that you have to slog through, but I 
think this example shows the main concepts.

Presumably in this new world order, the various gimple statement types 
will continue to inherit from a base class.  That seems somewhat 
inevitable and implies a certain amount of downcasting (via whatever 
means we agree upon).  The worry, in my mind is how pervasive the 
downcasting will be and how much of it we can get rid of over time.

I may be wrong, but ISTM some of the downcasting is a result of not 
providing certain capabilities via (pure?) virtual methods.  For 
example, expand_gimple_stmt_1 seems ripe for implementing as virtual 
methods.   ISTM you could also have virtuals to build the statements, 
dump/pretty-print them, verify them, branch/edge redirection, 
estimations for inlining, etc.  ISTM that would eliminate a good chunk 
of the downcasting.

Just to be clear, I'm not asking you to make those changes, just for 
your thoughts on approaches to eliminate the downcasting based on what 
we've seen so far.

Thanks for pulling this together to help illustrate how some of this 
might look in practice.  I hope others take the time to look closely as 
this example and think about what it means in terms of how we would be 
writing code 6 months from now.


Jeff
Michael Matz Nov. 14, 2013, 1:04 p.m. UTC | #2
Hi,

On Thu, 14 Nov 2013, Jeff Law wrote:

> Thanks.  It's pretty much what I expected.  Obviously for other codes 
> there may be a lot more changes that you have to slog through, but I 
> think this example shows the main concepts.
> 
> Presumably in this new world order, the various gimple statement types 
> will continue to inherit from a base class.  That seems somewhat 
> inevitable and implies a certain amount of downcasting (via whatever 
> means we agree upon). The worry, in my mind is how pervasive the 
> downcasting will be and how much of it we can get rid of over time.
> 
> I may be wrong, but ISTM some of the downcasting is a result of not 
> providing certain capabilities via (pure?) virtual methods.  For 
> example, expand_gimple_stmt_1 seems ripe for implementing as virtual 
> methods.

Please no.  A class with many methods hints at a bad design.  If we were 
to add virtual methods for every piece of the hundred passes that have to 
do different things per instruction code we'd arrive at exactly that.  
Even though most of these methods would be more related to the pass 
they're in they would actually have to be implemented in the gimple class 
(and their inherited ones).  I wouldn't want to see methods ala 
expand_me(), remove_me(), remove_me_for_predcom(), 
remove_me_for_some_other_pass(), optimize_me_for_{this,that,another}() and 
so on.

> ISTM you could also have virtuals to build the statements, 

Virtual to build things?  You mean constructors.

> dump/pretty-print them,

True.

> verify them,

Depends.  Part of them can be verified without context information, and 
that would perhaps be sensible in some virtual methods.  Part of the 
verification depends on context, other insns, the call graph, the CFG.  
Those should IMHO not be methods of gimple.

> branch/edge redirection, 

That seems to me more related to the cfg, not to statements.  Some 
statements need to be modified, true, but only very few subclasses (those 
that can transfer control).

> estimations for inlining,

Part of that (again the things you can determine with a statement 
alone, without much context, yes.

> etc.  ISTM that would eliminate a good chunk 
> of the downcasting.
> 
> Just to be clear, I'm not asking you to make those changes, just for 
> your thoughts on approaches to eliminate the downcasting based on what 
> we've seen so far.

Before adding a vtable pointer to gimple (or any other central, heavily 
used data structure) I'd go through great pain to avoid that.


Ciao,
Michael.
David Malcolm Nov. 14, 2013, 5:49 p.m. UTC | #3
On Thu, 2013-11-14 at 00:13 -0700, Jeff Law wrote:
> On 11/08/13 12:02, David Malcolm wrote:
> >> 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.
> [ ... ]
> 
> Thanks.  It's pretty much what I expected.  Obviously for other codes 
> there may be a lot more changes that you have to slog through, but I 
> think this example shows the main concepts.
> 
> Presumably in this new world order, the various gimple statement types 
> will continue to inherit from a base class.  That seems somewhat 
> inevitable and implies a certain amount of downcasting (via whatever 
> means we agree upon).  The worry, in my mind is how pervasive the 
> downcasting will be and how much of it we can get rid of over time.
> 
> I may be wrong, but ISTM some of the downcasting is a result of not 
> providing certain capabilities via (pure?) virtual methods.  For 
> example, expand_gimple_stmt_1 seems ripe for implementing as virtual 
> methods.   ISTM you could also have virtuals to build the statements, 
> dump/pretty-print them, verify them, branch/edge redirection, 
> estimations for inlining, etc.  ISTM that would eliminate a good chunk 
> of the downcasting.

FWIW, I prefer the downcasts to adding virtual functions; what I've
tried to do is create a very direct mapping from the status quo,
introducing inheritance to gain the benefits listed earlier in the
thread, whilst only changing "surface syntax".

It seems to me that we're considering the general problem of type-safe
code dispatch: given a type hierarchy, and various sites that want to
vary behavior based on what types they see, how best to invoke the
appropriate code, ensuring that the code that's called "knows" that its
dealing with the appropriate subclass i.e. in a typesafe manner.

There are various idioms for doing this kind of dispatch in C++, a
non-exhaustive list is:

   (a) switches and if/then tests on the GIMPLE_CODE (stmt) - the status
quo, and what my proposed patch continues to do, albeit gaining some
compile-time typechecking using as_a<> for the switch and dyn_cast<> for
the if/then.  This is changing some surface syntax without making major
changes, and gains us compile-time typesafety and IMHO more readable
code, though clearly opinions vary here.   In my (brief) testing, (a)
has no significant effect on compiler performance.

   (b) adding virtual functions to gimple would be another way to handle
type-safe dispatch, but they carry costs:
      (i) they would implicitly add a vtable ptr to the top of every
gimple statement, increasing the memory consumption of the process
      (ii) it's my belief that a virtual function call is more expensive
than the kinds of switch/if+then branching that we're currently doing on
the code - though I don't have measurements to back this up
      (iii) what I call "link-time granularity". A vtable references
every method within it.  I'd love to have a libgimple.so, but to do so,
every vtable would need to be populated with a particular set of
operations at link time - where do we draw the line for "core" gimple
operations, the dispatches performed by every core pass?   The set of
operations will never be complete: some plugin may want to add a new set
of per-gimple-subclass behaviors for some custom gimple pass.

  (c) the "Visitor" design pattern [1] - rather than adding virtual
functions to gimple, instead add them to a visitor class e.g.:

     class gimple_visitor
     {
     public:
	/* Visit a statement.  This will dispatch to the appropriate
	   handler below, based on GIMPLE_CODE (stmt), encapsulating
	   the appropriate downcast within a big switch statement.  */
	void visit_stmt (gimple stmt);

     protected:
	/* Each gimple code gets its own handler.  This class
	   provides an empty implementation of each.  If we want
	   to force overrides, we could have an abstract_gimple_visitor
	   base class above this one that has all of these be pure
	   virtual.  */
	virtual void visit_cond (gimple_cond stmt) {}
	virtual void visit_switch (gimple_switch stmt) {}
	virtual void visit_assign (gimple_assign stmt) {}
	virtual void visit_phi (gimple_phi phi) {}
	/* etc */
     };

   Example of a subclass:

     class gimple_pretty_printer : public gimple_visitor
     {
     protected:
	/* Each of these implements the subclass-specific
           pretty-printing logic.  */
	void visit_cond (gimple_cond stmt);
	void visit_switch (gimple_switch stmt);
	void visit_assign (gimple_assign stmt);
	void visit_phi (gimple_phi phi);
	/* etc */
     };

   so that the dispatch can be written like this:
     gimple_pretty_printer pp;
     pp.visit_stmt (stmt);

   (the above isn't *exactly* the Visitor pattern from the Gang of Four
book, I'm doing things in the visitor in order avoiding adding vfuncs to
gimple).

   This approach avoids adding an implicit vtable field to the top of
gimple [(i) above], and keeps the vtables with the code using them
[(iii) above].

  However it still would mean (ii) changing from switch/if-then control
flow to vfunc calls, with unknown impact on performance.  I'd be nervous
about adding virtual functions anywhere where we're not already jumping
though function ptrs.

  [Aside: this approach also gives us a natural place to store state
relating to the dispatch (as fields of the visitor subclass), which may
help in removing global state from the compiler.  (Doesn't help with GTY
state though)]

  (d) The status quo, with the drawback of doing the type-checking
either at run-time (checked build) or not at all (release build).

We have 41 gimple codes (and adding new ones is a relatively rare
event), but many more dispatch sites, I think - a first estimate might
be:
  [gcc] $ grep -nH -e "gimple_code (" *.c | wc -l
  772

So we have (I think) a large number of sites that dispatch to code based
on a (relatively) small fixed set of types - this suggests to me the use
of the Visitor pattern: (c) above, but I think (a) is the conservative
approach that gives many benefits for relatively low risk, and gives us
an easy transition path to (c) if measurement establishes the lack of
significant performance impact.  Such a transition could be done
piecemeal.

> Just to be clear, I'm not asking you to make those changes, just for 
> your thoughts on approaches to eliminate the downcasting based on what 
> we've seen so far.

(nods).   Note that I don't regard the downcasting as inherently bad,
just one approach to the generic issue of typesafe dynamic code
dispatch.   Yes, in many OO textbooks, it's regarded as a code smell,
but then again "goto" has its uses :)

> Thanks for pulling this together to help illustrate how some of this 
> might look in practice.  I hope others take the time to look closely as 
> this example and think about what it means in terms of how we would be 
> writing code 6 months from now.

On the subject of "6 months from now", my dream is that we can have a
libgimple.so and a librtl.so (.a in the regular builds).   I've love to
build a pluggable static analyzer on top of the gimple code - so I'm
trying to think of how we can structure the gimple code in such a way
that it's reusable in a modular way.

FWIW, I don't like the implicit "pointerness" of types within my
proposed patch, I'd rather have, say, the "gimple_switch" type be the
underlying _struct_, and spell out "gimple_switch *" to make it clear
that the latter is a pointer.

Doing so would make the is-a.h API somewhat less clunky, so that one
could write:

   if (gimple_switch *swtch = dyn_cast<gimple_switch> (stmt))
     {
	// do switchy stuff on swtch.
     }

rather than:

   if (gimple_switch swtch = dyn_cast<gimple_statement_switch> (stmt))
     {
	// do switchy stuff on swtch.
     }

Another tweak to the patch series could be to only introduce the leaf
subclasses one at a time, each time making use of the new subclass.  For
example, the "gimple_switch" subclass would be added at the same time as
a patch that makes use of it to improve compile-time typesafety, so each
patch would contain its own justification, as it were (applying the
YAGNI principle).

Sorry for the long email; thanks for reading to the end.
Dave

[1] see the Gang of Four "Design Pattens" book, or e.g.
http://en.wikipedia.org/wiki/Visitor_pattern
Jeff Law Nov. 14, 2013, 10:32 p.m. UTC | #4
On 11/14/13 10:49, David Malcolm wrote:
>
> FWIW, I prefer the downcasts to adding virtual functions; what I've
> tried to do is create a very direct mapping from the status quo,
> introducing inheritance to gain the benefits listed earlier in the
> thread, whilst only changing "surface syntax".
I understand (and I probably encouraged you to stay close as close to 
the status quo as possible while still moving this stuff forward ;-)


>
> It seems to me that we're considering the general problem of type-safe
> code dispatch: given a type hierarchy, and various sites that want to
> vary behavior based on what types they see, how best to invoke the
> appropriate code, ensuring that the code that's called "knows" that its
> dealing with the appropriate subclass i.e. in a typesafe manner.
Right.  Certainly in my quick browsing, this is primarily a dispatch 
problem.  I think Andrew had one in his Cauldron slide deck as well.

>
> There are various idioms for doing this kind of dispatch in C++, a
> non-exhaustive list is:
>
>     (a) switches and if/then tests on the GIMPLE_CODE (stmt) - the status
> quo,
Right.  And probably appropriate for now.  But I do want us to think 
about better ways to handle this.

>
>     (b) adding virtual functions to gimple would be another way to handle
> type-safe dispatch, but they carry costs:
>        (i) they would implicitly add a vtable ptr to the top of every
> gimple statement, increasing the memory consumption of the process
Thats my biggest concern.

>        (ii) it's my belief that a virtual function call is more expensive
> than the kinds of switch/if+then branching that we're currently doing on
> the code - though I don't have measurements to back this up
The virtual call is probably more expensive, but probably not as much as 
you might think as the switch likely compiles down to a multi-way branch 
which is on-par with an indirect call.


>
>    (c) the "Visitor" design pattern [1] - rather than adding virtual
> functions to gimple, instead add them to a visitor class e.g.:
Basically this just puts the vtable in a different class.  But doesn't 
the wrapping visitor need to know about the underlying details of the 
gimple statement class?   If we're trying to encapsulate things better, 
doesn't a visitor break the encapsulation?

>
>     (the above isn't *exactly* the Visitor pattern from the Gang of Four
> book, I'm doing things in the visitor in order avoiding adding vfuncs to
> gimple).
Right.  My mental model when I wrote my last message as a visit method 
which dispatched to the statement specific bits, but with the method as 
a part of the gimple base class.

>
>     This approach avoids adding an implicit vtable field to the top of
> gimple [(i) above], and keeps the vtables with the code using them
> [(iii) above].
Right.

>
>    However it still would mean (ii) changing from switch/if-then control
> flow to vfunc calls, with unknown impact on performance.  I'd be nervous
> about adding virtual functions anywhere where we're not already jumping
> though function ptrs.
As noted above, jumping through a function pointer probably isn't much 
different performance-wise than a multi-way branch.

Anyway, just wanted to get the conversation around this started as 
cleaning this stuff up is a natural follow-on at some point.

>
> (nods).   Note that I don't regard the downcasting as inherently bad,
> just one approach to the generic issue of typesafe dynamic code
> dispatch.   Yes, in many OO textbooks, it's regarded as a code smell,
> but then again "goto" has its uses :)
Again, my opinions come from working on large codes which did a lot of 
downcasting (and sadly upcasting too) and it was a major PITA to get 
sorted out.

Thanks,
jeff
diff mbox

Patch

commit b9e2375b4250428cc20e83c9be9be80afbfcb388
Author: David Malcolm <dmalcolm@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;
 }