diff mbox

Apply conditional down cast to cgraph.h et.al.

Message ID CAGqM8fa2dE4pzVOGLBXQfYfgJ7xRBsfmgMn-ZV7yq949nqmW_g@mail.gmail.com
State New
Headers show

Commit Message

Lawrence Crowl Oct. 29, 2012, 7:01 p.m. UTC
On 10/27/12, Marc Glisse <marc.glisse@inria.fr> wrote:
> On Fri, 26 Oct 2012, Lawrence Crowl wrote:
> > 2012-10-26  Lawrence Crowl  <crowl@google.com
>
> missing '>'

Fixed.

> > 	* is-a.h: New.
> > 	(is_a <T> (U*)): New.  Test for is-a relationship.
> > 	(as_a <T> (U*)): New.  Treat as a derived type.
> > 	(dyn_cast <T> (U*)): New.  Conditionally cast based on is_a.
>
> I can't find this file in the patch...

I forgot to svn add.  Updated patch here.


This patch implements generic type query and conversion functions,
and applies them to the use of cgraph_node, varpool_node, and symtab_node.

The functions are:

bool is_a <TYPE> (pointer)
  Tests whether the pointer actually points to a more derived TYPE.

TYPE *as_a <TYPE> (pointer)
  Converts pointer to a TYPE*.

TYPE *dyn_cast <TYPE> (pointer)
  Converts pointer to TYPE* if and only if "is_a <TYPE> pointer".
  Otherwise, returns NULL.
  This function is essentially a checked down cast.

These functions reduce compile time and increase type safety when treating a
generic item as a more specific item.  In essence, the code change is from

  if (symtab_function_p (node))
    {
      struct cgraph_node *cnode = cgraph (node);
      ....
    }

to

  if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
    {
      ....
    }

The necessary conditional test defines a variable that holds a known good
pointer to the specific item and avoids subsequent conversion calls and
the assertion checks that may come with them.

When, the property test is embedded within a larger condition, the variable
declaration gets pulled out of the condition.  (This leaves some room for
using the variable inappropriately.)

  if (symtab_variable_p (node)
      && varpool (node)->finalized)
    varpool_analyze_node (varpool (node));

becomes

  varpool_node *vnode = dyn_cast <varpool_node> (node);
  if (vnode && vnode->finalized)
    varpool_analyze_node (vnode);

Note that we have converted two sets of assertions in the calls to varpool
into safe and efficient use of a variable.


There are remaining calls to symtab_function_p and symtab_variable_p that
do not involve a pointer to a more specific type.  These have been converted
to calls to a functions is_a <cgraph_node> and is_a <varpool_node>.  The
original predicate functions have been removed.

The cgraph.h header defined both a struct and a function with the name
varpool_node.  This name overloading can cause some unintuitive error messages
when, as is common in C++, one omits the struct keyword when using the type.
I have renamed the function to varpool_node_for_decl.

Tested on x86_64.


Okay for trunk?
 }
@@ -1128,7 +1128,7 @@ lsei_start_function_in_partition (lto_sy

   if (lsei_end_p (lsei))
     return lsei;
-  if (!symtab_function_p (lsei_node (lsei))
+  if (!is_a <cgraph_node> (lsei_node (lsei))
       || !lto_symtab_encoder_in_partition_p (encoder, lsei_node (lsei)))
     lsei_next_function_in_partition (&lsei);

@@ -1141,7 +1141,7 @@ lsei_next_variable_in_partition (lto_sym
 {
   lsei_next (lsei);
   while (!lsei_end_p (*lsei)
-	 && (!symtab_variable_p (lsei_node (*lsei))
+	 && (!is_a <varpool_node> (lsei_node (*lsei))
 	     || !lto_symtab_encoder_in_partition_p (lsei->encoder, lsei_node
(*lsei))))
     lsei_next (lsei);
 }
@@ -1154,7 +1154,7 @@ lsei_start_variable_in_partition (lto_sy

   if (lsei_end_p (lsei))
     return lsei;
-  if (!symtab_variable_p (lsei_node (lsei))
+  if (!is_a <varpool_node> (lsei_node (lsei))
       || !lto_symtab_encoder_in_partition_p (encoder, lsei_node (lsei)))
     lsei_next_variable_in_partition (&lsei);

Comments

Diego Novillo Oct. 30, 2012, 12:20 p.m. UTC | #1
On 2012-10-29 15:01 , Lawrence Crowl wrote:
> On 10/27/12, Marc Glisse <marc.glisse@inria.fr> wrote:
>> On Fri, 26 Oct 2012, Lawrence Crowl wrote:
>>> 2012-10-26  Lawrence Crowl  <crowl@google.com
>>
>> missing '>'
>
> Fixed.
>
>>> 	* is-a.h: New.
>>> 	(is_a <T> (U*)): New.  Test for is-a relationship.
>>> 	(as_a <T> (U*)): New.  Treat as a derived type.
>>> 	(dyn_cast <T> (U*)): New.  Conditionally cast based on is_a.
>>
>> I can't find this file in the patch...
>
> I forgot to svn add.  Updated patch here.
>
>
> This patch implements generic type query and conversion functions,
> and applies them to the use of cgraph_node, varpool_node, and symtab_node.
>
> The functions are:
>
> bool is_a <TYPE> (pointer)
>    Tests whether the pointer actually points to a more derived TYPE.
>
> TYPE *as_a <TYPE> (pointer)
>    Converts pointer to a TYPE*.
>
> TYPE *dyn_cast <TYPE> (pointer)
>    Converts pointer to TYPE* if and only if "is_a <TYPE> pointer".
>    Otherwise, returns NULL.
>    This function is essentially a checked down cast.
>
> These functions reduce compile time and increase type safety when treating a
> generic item as a more specific item.  In essence, the code change is from
>
>    if (symtab_function_p (node))
>      {
>        struct cgraph_node *cnode = cgraph (node);
>        ....
>      }
>
> to
>
>    if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
>      {
>        ....
>      }
>
> The necessary conditional test defines a variable that holds a known good
> pointer to the specific item and avoids subsequent conversion calls and
> the assertion checks that may come with them.
>
> When, the property test is embedded within a larger condition, the variable
> declaration gets pulled out of the condition.  (This leaves some room for
> using the variable inappropriately.)
>
>    if (symtab_variable_p (node)
>        && varpool (node)->finalized)
>      varpool_analyze_node (varpool (node));
>
> becomes
>
>    varpool_node *vnode = dyn_cast <varpool_node> (node);
>    if (vnode && vnode->finalized)
>      varpool_analyze_node (vnode);
>
> Note that we have converted two sets of assertions in the calls to varpool
> into safe and efficient use of a variable.
>
>
> There are remaining calls to symtab_function_p and symtab_variable_p that
> do not involve a pointer to a more specific type.  These have been converted
> to calls to a functions is_a <cgraph_node> and is_a <varpool_node>.  The
> original predicate functions have been removed.
>
> The cgraph.h header defined both a struct and a function with the name
> varpool_node.  This name overloading can cause some unintuitive error messages
> when, as is common in C++, one omits the struct keyword when using the type.
> I have renamed the function to varpool_node_for_decl.
>
> Tested on x86_64.
>
>
> Okay for trunk?
> Index: gcc/ChangeLog
>
> 2012-10-29  Lawrence Crowl  <crowl@google.com>
>
> 	* is-a.h: New.
> 	(is_a <T> (U*)): New.  Test for is-a relationship.
> 	(as_a <T> (U*)): New.  Treat as a derived type.
> 	(dyn_cast <T> (U*)): New.  Conditionally cast based on is_a.
> 	* cgraph.h (varpool_node): Rename to varpool_node_for_decl.
> 	Adjust callers to match.
> 	(is_a_helper <cgraph_node>::test (symtab_node_def *)): New.
> 	(is_a_helper <varpool_node>::test (symtab_node_def *)): New.
> 	(symtab_node_def::try_function): New.  Change most calls to
> 	symtab_function_p with calls to dyn_cast <cgraph_node> (p).
> 	(symtab_node_def::try_variable): New.  Change most calls to
> 	symtab_variable_p with calls to dyn_cast <varpool_node> (p).
> 	(symtab_function_p): Remove.  Change callers to use
>          is_a <cgraph_node> (p) instead.
> 	(symtab_variable_p): Remove.  Change callers to use
>          is_a <varpool_node> (p) instead.
> 	* cgraph.c (cgraph_node_for_asm): Remove redundant call to
> 	symtab_node_for_asm.
> 	* cgraphunit.c (symbol_finalized_and_needed): New.
> 	(symbol_finalized): New.
> 	(cgraph_analyze_functions): Split complicated conditionals out into
> 	above new functions.
> 	* Makefile.in (CGRAPH_H): Add is-a.h as used by cgraph.h.

Thanks.  I really like this cleanup.  I have a few questions and 
comments below.  Honza, the patch looks OK to me but it touches a bunch 
of cgraph code, could you please go over it?


> Index: gcc/is-a.h
> ===================================================================
> --- gcc/is-a.h	(revision 0)
> +++ gcc/is-a.h	(revision 0)
> @@ -0,0 +1,118 @@
> +/* Dynamic testing for abstract is-a relationships.
> +   Copyright (C) 2012 Free Software Foundation, Inc.
> +   Contributed by Lawrence Crowl.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +
> +/*
> +
> +Suppose you have a symtab_node_def *ptr, AKA symtab_node ptr.  You can
> +test whether it points to a 'derived' cgraph_node as follows.
> +
> +  if (is_a <cgraph_node> (ptr))
> +    ....
> +
> +You can just assume that it is such a node.
> +
> +  do_something_with (as_a <cgraph_node> *ptr);
> +
> +You can test and obtain a pointer to the 'derived' type in one
> +indivisible operation.
> +
> +  if (cgraph_node *cptr = dyn_cast <cgraph_node> (ptr))
> +    ....
> +
> +
> +If you use these functions and get a 'inline function not defined' or
> +a 'missing symbol' error message for 'is_a_helper<....>::test', it
> +means that the connection between the types has not been made.  Each
> +connection between types must be made as follows.
> +
> +  template <>
> +  template <>
> +  inline bool
> +  is_a_helper <cgraph_node>::test (symtab_node_def *p)
> +  {
> +    return p->symbol.type == SYMTAB_FUNCTION;
> +  }
> +
> +
> +If a simple reinterpret_cast between the types is incorrect, then you
> +must specialize the cast function.  Failure to do so when needed may
> +result in a crash.
> +
> +  template <>
> +  template <>
> +  inline bool
> +  is_a_helper <cgraph_node>::cast (symtab_node_def *p)
> +  {
> +    return &p->x_function;
> +  }
> +

So, to use these three functions, the user must define this single 
'is_a_helper' routine?  Nothing else?

Could you add the explanation at the top of your message in the comments 
here?  I particularly liked this section:

 > bool is_a <TYPE> (pointer)
 >    Tests whether the pointer actually points to a more derived TYPE.
 >
 > TYPE *as_a <TYPE> (pointer)
 >    Converts pointer to a TYPE*.
 >
 > TYPE *dyn_cast <TYPE> (pointer)
 >    Converts pointer to TYPE* if and only if "is_a <TYPE> pointer".
 >    Otherwise, returns NULL.
 >    This function is essentially a checked down cast.
 >
 > These functions reduce compile time and increase type safety when
 > treating a
 > generic item as a more specific item.  In essence, the code change is
 > from
 >
 >    if (symtab_function_p (node))
 >      {
 >        struct cgraph_node *cnode = cgraph (node);
 >        ....
 >      }
 >
 > to
 >
 >    if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
 >      {
 >        ....
 >      }



> +*/
> +
> +#ifndef GCC_IS_A_H
> +#define GCC_IS_A_H
> +
> +
> +template <typename T>
> +struct is_a_helper
> +{
> +  template <typename U>
> +  static inline bool test (U *p);
> +  template <typename U>
> +  static inline T *cast (U *p);
> +};
> +

Those definitions you described at the top of your message would be very 
useful to have as lead-in comments to each of the functions below:

> +template <typename T>
> +template <typename U>
> +inline T *
> +is_a_helper <T>::cast (U *p)
> +{
> +  return reinterpret_cast <T *> (p);
> +}
> +
> +
> +template <typename T, typename U>
> +inline bool
> +is_a (U *p)
> +{
> +  return is_a_helper<T>::test (p);
> +}
> +
> +
> +template <typename T, typename U>
> +inline T *
> +as_a (U *p)
> +{
> +  gcc_assert (is_a <T> (p));
> +  return is_a_helper <T>::cast (p);
> +}
> +
> +
> +template <typename T, typename U>
> +inline T *
> +dyn_cast (U *p)
> +{
> +  if (is_a <T> (p))
> +    return is_a_helper <T>::cast (p);
> +  else
> +    return static_cast <T *> (0);
> +}
> +
> +#endif  /* GCC_IS_A_H  */
> Index: gcc/lto-symtab.c
> ===================================================================
> --- gcc/lto-symtab.c	(revision 192956)
> +++ gcc/lto-symtab.c	(working copy)
> @@ -532,11 +532,11 @@ lto_symtab_merge_cgraph_nodes_1 (symtab_
>
>         if (!symtab_real_symbol_p (e))
>   	continue;
> -      if (symtab_function_p (e)
> -	  && !DECL_BUILT_IN (e->symbol.decl))
> -	lto_cgraph_replace_node (cgraph (e), cgraph (prevailing));
> -      if (symtab_variable_p (e))
> -	lto_varpool_replace_node (varpool (e), varpool (prevailing));

> +      cgraph_node *ce = dyn_cast <cgraph_node> (e);
> +      if (ce && !DECL_BUILT_IN (e->symbol.decl))
> +	lto_cgraph_replace_node (ce, cgraph (prevailing));
> +      if (varpool_node *ve = dyn_cast <varpool_node> (e))
> +	lto_varpool_replace_node (ve, varpool (prevailing));

I see that you used dyn_cast<> differently here.  The first time, 'ce' 
is declared outside the if(), the second time, 've' is inside the if(). 
  Is this because 'ce' is used after the if()?

I think I prefer the form used for 've'.

> +
> +/* Determine if a symbol is finalized and needed.  */

s/a symbol/symbol NODE/.

> +
> +inline static bool
> +symbol_finalized_and_needed (symtab_node node)
> +{
> +  if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
> +    return cnode->local.finalized
> +	   && cgraph_decide_is_function_needed (cnode, cnode->symbol.decl);
> +  if (varpool_node *vnode = dyn_cast <varpool_node> (node))
> +    return vnode->finalized
> +	   && !DECL_EXTERNAL (vnode->symbol.decl)
> +	   && decide_is_variable_needed (vnode, vnode->symbol.decl);
> +  return false;
> +}
> +
> +/* Determine if a symbol is finalized.  */

Likewise.


Diego.
Richard Biener Oct. 30, 2012, 12:27 p.m. UTC | #2
On Tue, Oct 30, 2012 at 1:20 PM, Diego Novillo <dnovillo@google.com> wrote:
> On 2012-10-29 15:01 , Lawrence Crowl wrote:
>>
>> On 10/27/12, Marc Glisse <marc.glisse@inria.fr> wrote:
>>>
>>> On Fri, 26 Oct 2012, Lawrence Crowl wrote:
>>>>
>>>> 2012-10-26  Lawrence Crowl  <crowl@google.com
>>>
>>>
>>> missing '>'
>>
>>
>> Fixed.
>>
>>>>         * is-a.h: New.
>>>>         (is_a <T> (U*)): New.  Test for is-a relationship.
>>>>         (as_a <T> (U*)): New.  Treat as a derived type.
>>>>         (dyn_cast <T> (U*)): New.  Conditionally cast based on is_a.
>>>
>>>
>>> I can't find this file in the patch...
>>
>>
>> I forgot to svn add.  Updated patch here.
>>
>>
>> This patch implements generic type query and conversion functions,
>> and applies them to the use of cgraph_node, varpool_node, and symtab_node.
>>
>> The functions are:
>>
>> bool is_a <TYPE> (pointer)
>>    Tests whether the pointer actually points to a more derived TYPE.
>>
>> TYPE *as_a <TYPE> (pointer)
>>    Converts pointer to a TYPE*.
>>
>> TYPE *dyn_cast <TYPE> (pointer)
>>    Converts pointer to TYPE* if and only if "is_a <TYPE> pointer".
>>    Otherwise, returns NULL.
>>    This function is essentially a checked down cast.
>>
>> These functions reduce compile time and increase type safety when treating
>> a
>> generic item as a more specific item.  In essence, the code change is from
>>
>>    if (symtab_function_p (node))
>>      {
>>        struct cgraph_node *cnode = cgraph (node);
>>        ....
>>      }
>>
>> to
>>
>>    if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
>>      {
>>        ....
>>      }
>>
>> The necessary conditional test defines a variable that holds a known good
>> pointer to the specific item and avoids subsequent conversion calls and
>> the assertion checks that may come with them.
>>
>> When, the property test is embedded within a larger condition, the
>> variable
>> declaration gets pulled out of the condition.  (This leaves some room for
>> using the variable inappropriately.)
>>
>>    if (symtab_variable_p (node)
>>        && varpool (node)->finalized)
>>      varpool_analyze_node (varpool (node));
>>
>> becomes
>>
>>    varpool_node *vnode = dyn_cast <varpool_node> (node);
>>    if (vnode && vnode->finalized)
>>      varpool_analyze_node (vnode);
>>
>> Note that we have converted two sets of assertions in the calls to varpool
>> into safe and efficient use of a variable.
>>
>>
>> There are remaining calls to symtab_function_p and symtab_variable_p that
>> do not involve a pointer to a more specific type.  These have been
>> converted
>> to calls to a functions is_a <cgraph_node> and is_a <varpool_node>.  The
>> original predicate functions have been removed.
>>
>> The cgraph.h header defined both a struct and a function with the name
>> varpool_node.  This name overloading can cause some unintuitive error
>> messages
>> when, as is common in C++, one omits the struct keyword when using the
>> type.
>> I have renamed the function to varpool_node_for_decl.
>>
>> Tested on x86_64.
>>
>>
>> Okay for trunk?
>> Index: gcc/ChangeLog
>>
>> 2012-10-29  Lawrence Crowl  <crowl@google.com>
>>
>>         * is-a.h: New.
>>         (is_a <T> (U*)): New.  Test for is-a relationship.
>>         (as_a <T> (U*)): New.  Treat as a derived type.
>>         (dyn_cast <T> (U*)): New.  Conditionally cast based on is_a.
>>         * cgraph.h (varpool_node): Rename to varpool_node_for_decl.
>>         Adjust callers to match.
>>         (is_a_helper <cgraph_node>::test (symtab_node_def *)): New.
>>         (is_a_helper <varpool_node>::test (symtab_node_def *)): New.
>>         (symtab_node_def::try_function): New.  Change most calls to
>>         symtab_function_p with calls to dyn_cast <cgraph_node> (p).
>>         (symtab_node_def::try_variable): New.  Change most calls to
>>         symtab_variable_p with calls to dyn_cast <varpool_node> (p).
>>         (symtab_function_p): Remove.  Change callers to use
>>          is_a <cgraph_node> (p) instead.
>>         (symtab_variable_p): Remove.  Change callers to use
>>          is_a <varpool_node> (p) instead.
>>         * cgraph.c (cgraph_node_for_asm): Remove redundant call to
>>         symtab_node_for_asm.
>>         * cgraphunit.c (symbol_finalized_and_needed): New.
>>         (symbol_finalized): New.
>>         (cgraph_analyze_functions): Split complicated conditionals out
>> into
>>         above new functions.
>>         * Makefile.in (CGRAPH_H): Add is-a.h as used by cgraph.h.
>
>
> Thanks.  I really like this cleanup.  I have a few questions and comments
> below.  Honza, the patch looks OK to me but it touches a bunch of cgraph
> code, could you please go over it?
>
>
>
>> Index: gcc/is-a.h
>> ===================================================================
>> --- gcc/is-a.h  (revision 0)
>> +++ gcc/is-a.h  (revision 0)
>> @@ -0,0 +1,118 @@
>> +/* Dynamic testing for abstract is-a relationships.
>> +   Copyright (C) 2012 Free Software Foundation, Inc.
>> +   Contributed by Lawrence Crowl.
>> +
>> +This file is part of GCC.
>> +
>> +GCC is free software; you can redistribute it and/or modify it under
>> +the terms of the GNU General Public License as published by the Free
>> +Software Foundation; either version 3, or (at your option) any later
>> +version.
>> +
>> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
>> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>> +for more details.
>> +
>> +You should have received a copy of the GNU General Public License
>> +along with GCC; see the file COPYING3.  If not see
>> +<http://www.gnu.org/licenses/>.  */
>> +
>> +
>> +/*
>> +
>> +Suppose you have a symtab_node_def *ptr, AKA symtab_node ptr.  You can
>> +test whether it points to a 'derived' cgraph_node as follows.
>> +
>> +  if (is_a <cgraph_node> (ptr))
>> +    ....
>> +
>> +You can just assume that it is such a node.
>> +
>> +  do_something_with (as_a <cgraph_node> *ptr);
>> +
>> +You can test and obtain a pointer to the 'derived' type in one
>> +indivisible operation.
>> +
>> +  if (cgraph_node *cptr = dyn_cast <cgraph_node> (ptr))
>> +    ....
>> +
>> +
>> +If you use these functions and get a 'inline function not defined' or
>> +a 'missing symbol' error message for 'is_a_helper<....>::test', it
>> +means that the connection between the types has not been made.  Each
>> +connection between types must be made as follows.
>> +
>> +  template <>
>> +  template <>
>> +  inline bool
>> +  is_a_helper <cgraph_node>::test (symtab_node_def *p)
>> +  {
>> +    return p->symbol.type == SYMTAB_FUNCTION;
>> +  }
>> +
>> +
>> +If a simple reinterpret_cast between the types is incorrect, then you
>> +must specialize the cast function.  Failure to do so when needed may
>> +result in a crash.
>> +
>> +  template <>
>> +  template <>
>> +  inline bool
>> +  is_a_helper <cgraph_node>::cast (symtab_node_def *p)
>> +  {
>> +    return &p->x_function;
>> +  }
>> +
>
>
> So, to use these three functions, the user must define this single
> 'is_a_helper' routine?  Nothing else?
>
> Could you add the explanation at the top of your message in the comments
> here?

Some more comments would indeed be nice.  The patch is ok with that
and the other suggestions from Diego if Honza doesn't have any further
comments on the cgraph parts.

Thanks,
Richard.

>  I particularly liked this section:
>
>
>> bool is_a <TYPE> (pointer)
>>    Tests whether the pointer actually points to a more derived TYPE.
>>
>> TYPE *as_a <TYPE> (pointer)
>>    Converts pointer to a TYPE*.
>>
>> TYPE *dyn_cast <TYPE> (pointer)
>>    Converts pointer to TYPE* if and only if "is_a <TYPE> pointer".
>>    Otherwise, returns NULL.
>>    This function is essentially a checked down cast.
>>
>> These functions reduce compile time and increase type safety when
>> treating a
>> generic item as a more specific item.  In essence, the code change is
>> from
>>
>>    if (symtab_function_p (node))
>>      {
>>        struct cgraph_node *cnode = cgraph (node);
>>        ....
>>      }
>>
>> to
>>
>>    if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
>>      {
>>        ....
>>      }
>
>
>
>> +*/
>> +
>> +#ifndef GCC_IS_A_H
>> +#define GCC_IS_A_H
>> +
>> +
>> +template <typename T>
>> +struct is_a_helper
>> +{
>> +  template <typename U>
>> +  static inline bool test (U *p);
>> +  template <typename U>
>> +  static inline T *cast (U *p);
>> +};
>> +
>
>
> Those definitions you described at the top of your message would be very
> useful to have as lead-in comments to each of the functions below:
>
>
>> +template <typename T>
>> +template <typename U>
>> +inline T *
>> +is_a_helper <T>::cast (U *p)
>> +{
>> +  return reinterpret_cast <T *> (p);
>> +}
>> +
>> +
>> +template <typename T, typename U>
>> +inline bool
>> +is_a (U *p)
>> +{
>> +  return is_a_helper<T>::test (p);
>> +}
>> +
>> +
>> +template <typename T, typename U>
>> +inline T *
>> +as_a (U *p)
>> +{
>> +  gcc_assert (is_a <T> (p));
>> +  return is_a_helper <T>::cast (p);
>> +}
>> +
>> +
>> +template <typename T, typename U>
>> +inline T *
>> +dyn_cast (U *p)
>> +{
>> +  if (is_a <T> (p))
>> +    return is_a_helper <T>::cast (p);
>> +  else
>> +    return static_cast <T *> (0);
>> +}
>> +
>> +#endif  /* GCC_IS_A_H  */
>> Index: gcc/lto-symtab.c
>> ===================================================================
>> --- gcc/lto-symtab.c    (revision 192956)
>> +++ gcc/lto-symtab.c    (working copy)
>> @@ -532,11 +532,11 @@ lto_symtab_merge_cgraph_nodes_1 (symtab_
>>
>>         if (!symtab_real_symbol_p (e))
>>         continue;
>> -      if (symtab_function_p (e)
>> -         && !DECL_BUILT_IN (e->symbol.decl))
>> -       lto_cgraph_replace_node (cgraph (e), cgraph (prevailing));
>> -      if (symtab_variable_p (e))
>> -       lto_varpool_replace_node (varpool (e), varpool (prevailing));
>
>
>> +      cgraph_node *ce = dyn_cast <cgraph_node> (e);
>> +      if (ce && !DECL_BUILT_IN (e->symbol.decl))
>> +       lto_cgraph_replace_node (ce, cgraph (prevailing));
>> +      if (varpool_node *ve = dyn_cast <varpool_node> (e))
>> +       lto_varpool_replace_node (ve, varpool (prevailing));
>
>
> I see that you used dyn_cast<> differently here.  The first time, 'ce' is
> declared outside the if(), the second time, 've' is inside the if().  Is
> this because 'ce' is used after the if()?
>
> I think I prefer the form used for 've'.
>
>
>> +
>> +/* Determine if a symbol is finalized and needed.  */
>
>
> s/a symbol/symbol NODE/.
>
>
>> +
>> +inline static bool
>> +symbol_finalized_and_needed (symtab_node node)
>> +{
>> +  if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
>> +    return cnode->local.finalized
>> +          && cgraph_decide_is_function_needed (cnode,
>> cnode->symbol.decl);
>> +  if (varpool_node *vnode = dyn_cast <varpool_node> (node))
>> +    return vnode->finalized
>> +          && !DECL_EXTERNAL (vnode->symbol.decl)
>> +          && decide_is_variable_needed (vnode, vnode->symbol.decl);
>> +  return false;
>> +}
>> +
>> +/* Determine if a symbol is finalized.  */
>
>
> Likewise.
>
>
> Diego.
Jan Hubicka Oct. 30, 2012, 1:20 p.m. UTC | #3
> 2012-10-29  Lawrence Crowl  <crowl@google.com>
> 
> 	* is-a.h: New.
> 	(is_a <T> (U*)): New.  Test for is-a relationship.
> 	(as_a <T> (U*)): New.  Treat as a derived type.
> 	(dyn_cast <T> (U*)): New.  Conditionally cast based on is_a.
> 	* cgraph.h (varpool_node): Rename to varpool_node_for_decl.
> 	Adjust callers to match.
> 	(is_a_helper <cgraph_node>::test (symtab_node_def *)): New.
> 	(is_a_helper <varpool_node>::test (symtab_node_def *)): New.
> 	(symtab_node_def::try_function): New.  Change most calls to
> 	symtab_function_p with calls to dyn_cast <cgraph_node> (p).
> 	(symtab_node_def::try_variable): New.  Change most calls to
> 	symtab_variable_p with calls to dyn_cast <varpool_node> (p).
> 	(symtab_function_p): Remove.  Change callers to use
>         is_a <cgraph_node> (p) instead.
> 	(symtab_variable_p): Remove.  Change callers to use
>         is_a <varpool_node> (p) instead.
> 	* cgraph.c (cgraph_node_for_asm): Remove redundant call to
> 	symtab_node_for_asm.
> 	* cgraphunit.c (symbol_finalized_and_needed): New.
> 	(symbol_finalized): New.
> 	(cgraph_analyze_functions): Split complicated conditionals out into
> 	above new functions.
> 	* Makefile.in (CGRAPH_H): Add is-a.h as used by cgraph.h.
> 

the patch is OK,
thanks!
Honza
Lawrence Crowl Oct. 30, 2012, 8:53 p.m. UTC | #4
On 10/30/12, Diego Novillo <dnovillo@google.com> wrote:
> On 2012-10-29 15:01 , Lawrence Crowl wrote:
>> On 10/27/12, Marc Glisse <marc.glisse@inria.fr> wrote:
>>> On Fri, 26 Oct 2012, Lawrence Crowl wrote:
>>>> 2012-10-26  Lawrence Crowl  <crowl@google.com
>>>
>>> missing '>'
>>
>> Fixed.
>>
>>>> 	* is-a.h: New.
>>>> 	(is_a <T> (U*)): New.  Test for is-a relationship.
>>>> 	(as_a <T> (U*)): New.  Treat as a derived type.
>>>> 	(dyn_cast <T> (U*)): New.  Conditionally cast based on is_a.
>>>
>>> I can't find this file in the patch...
>>
>> I forgot to svn add.  Updated patch here.
>>
>>
>> This patch implements generic type query and conversion functions,
>> and applies them to the use of cgraph_node, varpool_node, and
>> symtab_node.
>>
>> The functions are:
>>
>> bool is_a <TYPE> (pointer)
>>    Tests whether the pointer actually points to a more derived TYPE.
>>
>> TYPE *as_a <TYPE> (pointer)
>>    Converts pointer to a TYPE*.
>>
>> TYPE *dyn_cast <TYPE> (pointer)
>>    Converts pointer to TYPE* if and only if "is_a <TYPE> pointer".
>>    Otherwise, returns NULL.
>>    This function is essentially a checked down cast.
>>
>> These functions reduce compile time and increase type safety when treating
>> a
>> generic item as a more specific item.  In essence, the code change is
>> from
>>
>>    if (symtab_function_p (node))
>>      {
>>        struct cgraph_node *cnode = cgraph (node);
>>        ....
>>      }
>>
>> to
>>
>>    if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
>>      {
>>        ....
>>      }
>>
>> The necessary conditional test defines a variable that holds a known good
>> pointer to the specific item and avoids subsequent conversion calls and
>> the assertion checks that may come with them.
>>
>> When, the property test is embedded within a larger condition, the
>> variable
>> declaration gets pulled out of the condition.  (This leaves some room for
>> using the variable inappropriately.)
>>
>>    if (symtab_variable_p (node)
>>        && varpool (node)->finalized)
>>      varpool_analyze_node (varpool (node));
>>
>> becomes
>>
>>    varpool_node *vnode = dyn_cast <varpool_node> (node);
>>    if (vnode && vnode->finalized)
>>      varpool_analyze_node (vnode);
>>
>> Note that we have converted two sets of assertions in the calls to
>> varpool
>> into safe and efficient use of a variable.
>>
>>
>> There are remaining calls to symtab_function_p and symtab_variable_p that
>> do not involve a pointer to a more specific type.  These have been
>> converted
>> to calls to a functions is_a <cgraph_node> and is_a <varpool_node>.  The
>> original predicate functions have been removed.
>>
>> The cgraph.h header defined both a struct and a function with the name
>> varpool_node.  This name overloading can cause some unintuitive error
>> messages
>> when, as is common in C++, one omits the struct keyword when using the
>> type.
>> I have renamed the function to varpool_node_for_decl.
>>
>> Tested on x86_64.
>>
>>
>> Okay for trunk?
>> Index: gcc/ChangeLog
>>
>> 2012-10-29  Lawrence Crowl  <crowl@google.com>
>>
>> 	* is-a.h: New.
>> 	(is_a <T> (U*)): New.  Test for is-a relationship.
>> 	(as_a <T> (U*)): New.  Treat as a derived type.
>> 	(dyn_cast <T> (U*)): New.  Conditionally cast based on is_a.
>> 	* cgraph.h (varpool_node): Rename to varpool_node_for_decl.
>> 	Adjust callers to match.
>> 	(is_a_helper <cgraph_node>::test (symtab_node_def *)): New.
>> 	(is_a_helper <varpool_node>::test (symtab_node_def *)): New.
>> 	(symtab_node_def::try_function): New.  Change most calls to
>> 	symtab_function_p with calls to dyn_cast <cgraph_node> (p).
>> 	(symtab_node_def::try_variable): New.  Change most calls to
>> 	symtab_variable_p with calls to dyn_cast <varpool_node> (p).
>> 	(symtab_function_p): Remove.  Change callers to use
>>          is_a <cgraph_node> (p) instead.
>> 	(symtab_variable_p): Remove.  Change callers to use
>>          is_a <varpool_node> (p) instead.
>> 	* cgraph.c (cgraph_node_for_asm): Remove redundant call to
>> 	symtab_node_for_asm.
>> 	* cgraphunit.c (symbol_finalized_and_needed): New.
>> 	(symbol_finalized): New.
>> 	(cgraph_analyze_functions): Split complicated conditionals out into
>> 	above new functions.
>> 	* Makefile.in (CGRAPH_H): Add is-a.h as used by cgraph.h.
>
> Thanks.  I really like this cleanup.  I have a few questions and
> comments below.  Honza, the patch looks OK to me but it touches a bunch
> of cgraph code, could you please go over it?
>
>
>> Index: gcc/is-a.h
>> ===================================================================
>> --- gcc/is-a.h	(revision 0)
>> +++ gcc/is-a.h	(revision 0)
>> @@ -0,0 +1,118 @@
>> +/* Dynamic testing for abstract is-a relationships.
>> +   Copyright (C) 2012 Free Software Foundation, Inc.
>> +   Contributed by Lawrence Crowl.
>> +
>> +This file is part of GCC.
>> +
>> +GCC is free software; you can redistribute it and/or modify it under
>> +the terms of the GNU General Public License as published by the Free
>> +Software Foundation; either version 3, or (at your option) any later
>> +version.
>> +
>> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
>> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>> +for more details.
>> +
>> +You should have received a copy of the GNU General Public License
>> +along with GCC; see the file COPYING3.  If not see
>> +<http://www.gnu.org/licenses/>.  */
>> +
>> +
>> +/*
>> +
>> +Suppose you have a symtab_node_def *ptr, AKA symtab_node ptr.  You can
>> +test whether it points to a 'derived' cgraph_node as follows.
>> +
>> +  if (is_a <cgraph_node> (ptr))
>> +    ....
>> +
>> +You can just assume that it is such a node.
>> +
>> +  do_something_with (as_a <cgraph_node> *ptr);
>> +
>> +You can test and obtain a pointer to the 'derived' type in one
>> +indivisible operation.
>> +
>> +  if (cgraph_node *cptr = dyn_cast <cgraph_node> (ptr))
>> +    ....
>> +
>> +
>> +If you use these functions and get a 'inline function not defined' or
>> +a 'missing symbol' error message for 'is_a_helper<....>::test', it
>> +means that the connection between the types has not been made.  Each
>> +connection between types must be made as follows.
>> +
>> +  template <>
>> +  template <>
>> +  inline bool
>> +  is_a_helper <cgraph_node>::test (symtab_node_def *p)
>> +  {
>> +    return p->symbol.type == SYMTAB_FUNCTION;
>> +  }
>> +
>> +
>> +If a simple reinterpret_cast between the types is incorrect, then you
>> +must specialize the cast function.  Failure to do so when needed may
>> +result in a crash.
>> +
>> +  template <>
>> +  template <>
>> +  inline bool
>> +  is_a_helper <cgraph_node>::cast (symtab_node_def *p)
>> +  {
>> +    return &p->x_function;
>> +  }
>> +
>
> So, to use these three functions, the user must define this single
> 'is_a_helper' routine?  Nothing else?

You need to distinguish which kind user.  Someone just wanting
to convert does not need to know about the is_a_helper stuff.
Someone wanting to extend the set of type relationships needs to
provide one or two template specializations.  I've modified the
in-header documentation to better reflect the distinction.

> Could you add the explanation at the top of your message in the comments
> here?  I particularly liked this section:

I've merge the patch description into the in-header comments.

>  > bool is_a <TYPE> (pointer)
>  >    Tests whether the pointer actually points to a more derived TYPE.
>  >
>  > TYPE *as_a <TYPE> (pointer)
>  >    Converts pointer to a TYPE*.
>  >
>  > TYPE *dyn_cast <TYPE> (pointer)
>  >    Converts pointer to TYPE* if and only if "is_a <TYPE> pointer".
>  >    Otherwise, returns NULL.
>  >    This function is essentially a checked down cast.
>  >
>  > These functions reduce compile time and increase type safety when
>  > treating a
>  > generic item as a more specific item.  In essence, the code change is
>  > from
>  >
>  >    if (symtab_function_p (node))
>  >      {
>  >        struct cgraph_node *cnode = cgraph (node);
>  >        ....
>  >      }
>  >
>  > to
>  >
>  >    if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
>  >      {
>  >        ....
>  >      }
>
>
>
>> +*/
>> +
>> +#ifndef GCC_IS_A_H
>> +#define GCC_IS_A_H
>> +
>> +
>> +template <typename T>
>> +struct is_a_helper
>> +{
>> +  template <typename U>
>> +  static inline bool test (U *p);
>> +  template <typename U>
>> +  static inline T *cast (U *p);
>> +};
>> +
>
> Those definitions you described at the top of your message would be very
> useful to have as lead-in comments to each of the functions below:

Updated.

>
>> +template <typename T>
>> +template <typename U>
>> +inline T *
>> +is_a_helper <T>::cast (U *p)
>> +{
>> +  return reinterpret_cast <T *> (p);
>> +}
>> +
>> +
>> +template <typename T, typename U>
>> +inline bool
>> +is_a (U *p)
>> +{
>> +  return is_a_helper<T>::test (p);
>> +}
>> +
>> +
>> +template <typename T, typename U>
>> +inline T *
>> +as_a (U *p)
>> +{
>> +  gcc_assert (is_a <T> (p));
>> +  return is_a_helper <T>::cast (p);
>> +}
>> +
>> +
>> +template <typename T, typename U>
>> +inline T *
>> +dyn_cast (U *p)
>> +{
>> +  if (is_a <T> (p))
>> +    return is_a_helper <T>::cast (p);
>> +  else
>> +    return static_cast <T *> (0);
>> +}
>> +
>> +#endif  /* GCC_IS_A_H  */
>> Index: gcc/lto-symtab.c
>> ===================================================================
>> --- gcc/lto-symtab.c	(revision 192956)
>> +++ gcc/lto-symtab.c	(working copy)
>> @@ -532,11 +532,11 @@ lto_symtab_merge_cgraph_nodes_1 (symtab_
>>
>>         if (!symtab_real_symbol_p (e))
>>   	continue;
>> -      if (symtab_function_p (e)
>> -	  && !DECL_BUILT_IN (e->symbol.decl))
>> -	lto_cgraph_replace_node (cgraph (e), cgraph (prevailing));
>> -      if (symtab_variable_p (e))
>> -	lto_varpool_replace_node (varpool (e), varpool (prevailing));
>
>> +      cgraph_node *ce = dyn_cast <cgraph_node> (e);
>> +      if (ce && !DECL_BUILT_IN (e->symbol.decl))
>> +	lto_cgraph_replace_node (ce, cgraph (prevailing));
>> +      if (varpool_node *ve = dyn_cast <varpool_node> (e))
>> +	lto_varpool_replace_node (ve, varpool (prevailing));
>
> I see that you used dyn_cast<> differently here.  The first time, 'ce'
> is declared outside the if(), the second time, 've' is inside the if().
>   Is this because 'ce' is used after the if()?

It's because in the first case it is a composite conditional.

> I think I prefer the form used for 've'.

I originally had

  if (cgraph_node *ce = dyn_cast <cgraph_node> (e))
    if (!DECL_BUILT_IN (e->symbol.decl))
      lto_cgraph_replace_node (ce, cgraph (prevailing));

but folks objected to increasing the nesting, and asked that I
change to the pre-declare form.

>> +
>> +/* Determine if a symbol is finalized and needed.  */
>
> s/a symbol/symbol NODE/.

Fixed.

>
>> +
>> +inline static bool
>> +symbol_finalized_and_needed (symtab_node node)
>> +{
>> +  if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
>> +    return cnode->local.finalized
>> +	   && cgraph_decide_is_function_needed (cnode, cnode->symbol.decl);
>> +  if (varpool_node *vnode = dyn_cast <varpool_node> (node))
>> +    return vnode->finalized
>> +	   && !DECL_EXTERNAL (vnode->symbol.decl)
>> +	   && decide_is_variable_needed (vnode, vnode->symbol.decl);
>> +  return false;
>> +}
>> +
>> +/* Determine if a symbol is finalized.  */
>
> Likewise.

Fixed.
Diego Novillo Oct. 30, 2012, 9:06 p.m. UTC | #5
On Tue, Oct 30, 2012 at 4:53 PM, Lawrence Crowl <crowl@googlers.com> wrote:
> On 10/30/12, Diego Novillo <dnovillo@google.com> wrote:
>>
>> So, to use these three functions, the user must define this single
>> 'is_a_helper' routine?  Nothing else?
>
> You need to distinguish which kind user.  Someone just wanting
> to convert does not need to know about the is_a_helper stuff.
> Someone wanting to extend the set of type relationships needs to
> provide one or two template specializations.  I've modified the
> in-header documentation to better reflect the distinction.

Great.

> I originally had
>
>   if (cgraph_node *ce = dyn_cast <cgraph_node> (e))
>     if (!DECL_BUILT_IN (e->symbol.decl))
>       lto_cgraph_replace_node (ce, cgraph (prevailing));
>
> but folks objected to increasing the nesting, and asked that I
> change to the pre-declare form.

Ah, yeah.  I remember that.  OK, so we can now use both forms, right?


Thanks.  Diego.
Lawrence Crowl Oct. 30, 2012, 9:09 p.m. UTC | #6
On 10/30/12, Diego Novillo <dnovillo@google.com> wrote:
> On Tue, Oct 30, 2012 at 4:53 PM, Lawrence Crowl <crowl@googlers.com> wrote:
>> On 10/30/12, Diego Novillo <dnovillo@google.com> wrote:
>>>
>>> So, to use these three functions, the user must define this single
>>> 'is_a_helper' routine?  Nothing else?
>>
>> You need to distinguish which kind user.  Someone just wanting
>> to convert does not need to know about the is_a_helper stuff.
>> Someone wanting to extend the set of type relationships needs to
>> provide one or two template specializations.  I've modified the
>> in-header documentation to better reflect the distinction.
>
> Great.
>
>> I originally had
>>
>>   if (cgraph_node *ce = dyn_cast <cgraph_node> (e))
>>     if (!DECL_BUILT_IN (e->symbol.decl))
>>       lto_cgraph_replace_node (ce, cgraph (prevailing));
>>
>> but folks objected to increasing the nesting, and asked that I
>> change to the pre-declare form.
>
> Ah, yeah.  I remember that.  OK, so we can now use both forms, right?

Yes.

I will commit the patch as soon as the merge and test is complete.
Xinliang David Li Oct. 30, 2012, 9:21 p.m. UTC | #7
Good cleanup! Simple and consistent interfaces are usually
self-documenting, and this one is a good step forward.

thanks,

David

On Tue, Oct 30, 2012 at 2:09 PM, Lawrence Crowl <crowl@googlers.com> wrote:
> On 10/30/12, Diego Novillo <dnovillo@google.com> wrote:
>> On Tue, Oct 30, 2012 at 4:53 PM, Lawrence Crowl <crowl@googlers.com> wrote:
>>> On 10/30/12, Diego Novillo <dnovillo@google.com> wrote:
>>>>
>>>> So, to use these three functions, the user must define this single
>>>> 'is_a_helper' routine?  Nothing else?
>>>
>>> You need to distinguish which kind user.  Someone just wanting
>>> to convert does not need to know about the is_a_helper stuff.
>>> Someone wanting to extend the set of type relationships needs to
>>> provide one or two template specializations.  I've modified the
>>> in-header documentation to better reflect the distinction.
>>
>> Great.
>>
>>> I originally had
>>>
>>>   if (cgraph_node *ce = dyn_cast <cgraph_node> (e))
>>>     if (!DECL_BUILT_IN (e->symbol.decl))
>>>       lto_cgraph_replace_node (ce, cgraph (prevailing));
>>>
>>> but folks objected to increasing the nesting, and asked that I
>>> change to the pre-declare form.
>>
>> Ah, yeah.  I remember that.  OK, so we can now use both forms, right?
>
> Yes.
>
> I will commit the patch as soon as the merge and test is complete.
>
> --
> Lawrence Crowl
diff mbox

Patch

Index: gcc/ChangeLog

2012-10-29  Lawrence Crowl  <crowl@google.com>

	* is-a.h: New.
	(is_a <T> (U*)): New.  Test for is-a relationship.
	(as_a <T> (U*)): New.  Treat as a derived type.
	(dyn_cast <T> (U*)): New.  Conditionally cast based on is_a.
	* cgraph.h (varpool_node): Rename to varpool_node_for_decl.
	Adjust callers to match.
	(is_a_helper <cgraph_node>::test (symtab_node_def *)): New.
	(is_a_helper <varpool_node>::test (symtab_node_def *)): New.
	(symtab_node_def::try_function): New.  Change most calls to
	symtab_function_p with calls to dyn_cast <cgraph_node> (p).
	(symtab_node_def::try_variable): New.  Change most calls to
	symtab_variable_p with calls to dyn_cast <varpool_node> (p).
	(symtab_function_p): Remove.  Change callers to use
        is_a <cgraph_node> (p) instead.
	(symtab_variable_p): Remove.  Change callers to use
        is_a <varpool_node> (p) instead.
	* cgraph.c (cgraph_node_for_asm): Remove redundant call to
	symtab_node_for_asm.
	* cgraphunit.c (symbol_finalized_and_needed): New.
	(symbol_finalized): New.
	(cgraph_analyze_functions): Split complicated conditionals out into
	above new functions.
	* Makefile.in (CGRAPH_H): Add is-a.h as used by cgraph.h.

Index: gcc/is-a.h
===================================================================
--- gcc/is-a.h	(revision 0)
+++ gcc/is-a.h	(revision 0)
@@ -0,0 +1,118 @@ 
+/* Dynamic testing for abstract is-a relationships.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Contributed by Lawrence Crowl.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+
+/*
+
+Suppose you have a symtab_node_def *ptr, AKA symtab_node ptr.  You can
+test whether it points to a 'derived' cgraph_node as follows.
+
+  if (is_a <cgraph_node> (ptr))
+    ....
+
+You can just assume that it is such a node.
+
+  do_something_with (as_a <cgraph_node> *ptr);
+
+You can test and obtain a pointer to the 'derived' type in one
+indivisible operation.
+
+  if (cgraph_node *cptr = dyn_cast <cgraph_node> (ptr))
+    ....
+
+
+If you use these functions and get a 'inline function not defined' or
+a 'missing symbol' error message for 'is_a_helper<....>::test', it
+means that the connection between the types has not been made.  Each
+connection between types must be made as follows.
+
+  template <>
+  template <>
+  inline bool
+  is_a_helper <cgraph_node>::test (symtab_node_def *p)
+  {
+    return p->symbol.type == SYMTAB_FUNCTION;
+  }
+
+
+If a simple reinterpret_cast between the types is incorrect, then you
+must specialize the cast function.  Failure to do so when needed may
+result in a crash.
+
+  template <>
+  template <>
+  inline bool
+  is_a_helper <cgraph_node>::cast (symtab_node_def *p)
+  {
+    return &p->x_function;
+  }
+
+*/
+
+#ifndef GCC_IS_A_H
+#define GCC_IS_A_H
+
+
+template <typename T>
+struct is_a_helper
+{
+  template <typename U>
+  static inline bool test (U *p);
+  template <typename U>
+  static inline T *cast (U *p);
+};
+
+template <typename T>
+template <typename U>
+inline T *
+is_a_helper <T>::cast (U *p)
+{
+  return reinterpret_cast <T *> (p);
+}
+
+
+template <typename T, typename U>
+inline bool
+is_a (U *p)
+{
+  return is_a_helper<T>::test (p);
+}
+
+
+template <typename T, typename U>
+inline T *
+as_a (U *p)
+{
+  gcc_assert (is_a <T> (p));
+  return is_a_helper <T>::cast (p);
+}
+
+
+template <typename T, typename U>
+inline T *
+dyn_cast (U *p)
+{
+  if (is_a <T> (p))
+    return is_a_helper <T>::cast (p);
+  else
+    return static_cast <T *> (0);
+}
+
+#endif  /* GCC_IS_A_H  */
Index: gcc/lto-symtab.c
===================================================================
--- gcc/lto-symtab.c	(revision 192956)
+++ gcc/lto-symtab.c	(working copy)
@@ -532,11 +532,11 @@  lto_symtab_merge_cgraph_nodes_1 (symtab_

       if (!symtab_real_symbol_p (e))
 	continue;
-      if (symtab_function_p (e)
-	  && !DECL_BUILT_IN (e->symbol.decl))
-	lto_cgraph_replace_node (cgraph (e), cgraph (prevailing));
-      if (symtab_variable_p (e))
-	lto_varpool_replace_node (varpool (e), varpool (prevailing));
+      cgraph_node *ce = dyn_cast <cgraph_node> (e);
+      if (ce && !DECL_BUILT_IN (e->symbol.decl))
+	lto_cgraph_replace_node (ce, cgraph (prevailing));
+      if (varpool_node *ve = dyn_cast <varpool_node> (e))
+	lto_varpool_replace_node (ve, varpool (prevailing));
     }

   return;
Index: gcc/cgraphbuild.c
===================================================================
--- gcc/cgraphbuild.c	(revision 192956)
+++ gcc/cgraphbuild.c	(working copy)
@@ -84,7 +84,7 @@  record_reference (tree *tp, int *walk_su

       if (TREE_CODE (decl) == VAR_DECL)
 	{
-	  struct varpool_node *vnode = varpool_node (decl);
+	  struct varpool_node *vnode = varpool_node_for_decl (decl);
 	  ipa_record_reference ((symtab_node)ctx->varpool_node,
 				(symtab_node)vnode,
 				IPA_REF_ADDR, NULL);
@@ -123,7 +123,7 @@  record_type_list (struct cgraph_node *no
 	  type = TREE_OPERAND (type, 0);
 	  if (TREE_CODE (type) == VAR_DECL)
 	    {
-	      struct varpool_node *vnode = varpool_node (type);
+	      struct varpool_node *vnode = varpool_node_for_decl (type);
 	      ipa_record_reference ((symtab_node)node,
 				    (symtab_node)vnode,
 				    IPA_REF_ADDR, NULL);
@@ -233,7 +233,7 @@  mark_address (gimple stmt, tree addr, vo
   else if (addr && TREE_CODE (addr) == VAR_DECL
 	   && (TREE_STATIC (addr) || DECL_EXTERNAL (addr)))
     {
-      struct varpool_node *vnode = varpool_node (addr);
+      struct varpool_node *vnode = varpool_node_for_decl (addr);

       ipa_record_reference ((symtab_node)data,
 			    (symtab_node)vnode,
@@ -262,7 +262,7 @@  mark_load (gimple stmt, tree t, void *da
   else if (t && TREE_CODE (t) == VAR_DECL
 	   && (TREE_STATIC (t) || DECL_EXTERNAL (t)))
     {
-      struct varpool_node *vnode = varpool_node (t);
+      struct varpool_node *vnode = varpool_node_for_decl (t);

       ipa_record_reference ((symtab_node)data,
 			    (symtab_node)vnode,
@@ -280,7 +280,7 @@  mark_store (gimple stmt, tree t, void *d
   if (t && TREE_CODE (t) == VAR_DECL
       && (TREE_STATIC (t) || DECL_EXTERNAL (t)))
     {
-      struct varpool_node *vnode = varpool_node (t);
+      struct varpool_node *vnode = varpool_node_for_decl (t);

       ipa_record_reference ((symtab_node)data,
 			    (symtab_node)vnode,
@@ -392,7 +392,7 @@  void
 record_references_in_initializer (tree decl, bool only_vars)
 {
   struct pointer_set_t *visited_nodes = pointer_set_create ();
-  struct varpool_node *node = varpool_node (decl);
+  struct varpool_node *node = varpool_node_for_decl (decl);
   struct record_reference_ctx ctx = {false, NULL};

   ctx.varpool_node = node;
Index: gcc/cgraph.c
===================================================================
--- gcc/cgraph.c	(revision 192956)
+++ gcc/cgraph.c	(working copy)
@@ -503,12 +503,15 @@  cgraph_add_thunk (struct cgraph_node *de
 struct cgraph_node *
 cgraph_node_for_asm (tree asmname)
 {
-  symtab_node node = symtab_node_for_asm (asmname);
-
   /* We do not want to look at inline clones.  */
-  for (node = symtab_node_for_asm (asmname); node; node =
node->symbol.next_sharing_asm_name)
-    if (symtab_function_p (node) && !cgraph(node)->global.inlined_to)
-      return cgraph (node);
+  for (symtab_node node = symtab_node_for_asm (asmname);
+       node;
+       node = node->symbol.next_sharing_asm_name)
+    {
+      cgraph_node *cn = dyn_cast <cgraph_node> (node);
+      if (cn && !cn->global.inlined_to)
+	return cn;
+    }
   return NULL;
 }

Index: gcc/cgraph.h
===================================================================
--- gcc/cgraph.h	(revision 192956)
+++ gcc/cgraph.h	(working copy)
@@ -22,6 +22,7 @@  along with GCC; see the file COPYING3.
 #ifndef GCC_CGRAPH_H
 #define GCC_CGRAPH_H

+#include "is-a.h"
 #include "plugin-api.h"
 #include "vec.h"
 #include "tree.h"
@@ -457,12 +458,32 @@  struct GTY(()) asm_node {
 union GTY((desc ("%h.symbol.type"), chain_next ("%h.symbol.next"),
 	   chain_prev ("%h.symbol.previous"))) symtab_node_def {
   struct symtab_node_base GTY ((tag ("SYMTAB_SYMBOL"))) symbol;
-  /* Use cgraph (symbol) accessor to get cgraph_node.  */
+  /* To access the following fields,
+     use the use dyn_cast or as_a to obtain the concrete type.  */
   struct cgraph_node GTY ((tag ("SYMTAB_FUNCTION"))) x_function;
-  /* Use varpool (symbol) accessor to get varpool_node.  */
   struct varpool_node GTY ((tag ("SYMTAB_VARIABLE"))) x_variable;
 };

+/* Report whether or not THIS symtab node is a function, aka cgraph_node.  */
+
+template <>
+template <>
+inline bool
+is_a_helper <cgraph_node>::test (symtab_node_def *p)
+{
+  return p->symbol.type == SYMTAB_FUNCTION;
+}
+
+/* Report whether or not THIS symtab node is a vriable, aka varpool_node.  */
+
+template <>
+template <>
+inline bool
+is_a_helper <varpool_node>::test (symtab_node_def *p)
+{
+  return p->symbol.type == SYMTAB_VARIABLE;
+}
+
 extern GTY(()) symtab_node symtab_nodes;
 extern GTY(()) int cgraph_n_nodes;
 extern GTY(()) int cgraph_max_uid;
@@ -685,7 +706,7 @@  bool cgraph_maybe_hot_edge_p (struct cgr
 bool cgraph_optimize_for_size_p (struct cgraph_node *);

 /* In varpool.c  */
-struct varpool_node *varpool_node (tree);
+struct varpool_node *varpool_node_for_decl (tree);
 struct varpool_node *varpool_node_for_asm (tree asmname);
 void varpool_mark_needed_node (struct varpool_node *);
 void debug_varpool (void);
@@ -715,19 +736,6 @@  void varpool_add_new_variable (tree);
 void symtab_initialize_asm_name_hash (void);
 void symtab_prevail_in_asm_name_hash (symtab_node node);

-/* Return true when NODE is function.  */
-static inline bool
-symtab_function_p (symtab_node node)
-{
-  return node->symbol.type == SYMTAB_FUNCTION;
-}
-
-/* Return true when NODE is variable.  */
-static inline bool
-symtab_variable_p (symtab_node node)
-{
-  return node->symbol.type == SYMTAB_VARIABLE;
-}

 /* Return callgraph node for given symbol and check it is a function. */
 static inline struct cgraph_node *
@@ -800,10 +808,8 @@  varpool_first_variable (void)
 {
   symtab_node node;
   for (node = symtab_nodes; node; node = node->symbol.next)
-    {
-      if (symtab_variable_p (node))
-	return varpool (node);
-    }
+    if (varpool_node *vnode = dyn_cast <varpool_node> (node))
+      return vnode;
   return NULL;
 }

@@ -813,10 +819,8 @@  varpool_next_variable (struct varpool_no
 {
   symtab_node node1 = (symtab_node) node->symbol.next;
   for (; node1; node1 = node1->symbol.next)
-    {
-      if (symtab_variable_p (node1))
-	return varpool (node1);
-    }
+    if (varpool_node *vnode1 = dyn_cast <varpool_node> (node1))
+      return vnode1;
   return NULL;
 }
 /* Walk all variables.  */
@@ -832,9 +836,9 @@  varpool_first_static_initializer (void)
   symtab_node node;
   for (node = symtab_nodes; node; node = node->symbol.next)
     {
-      if (symtab_variable_p (node)
-	  && DECL_INITIAL (node->symbol.decl))
-	return varpool (node);
+      varpool_node *vnode = dyn_cast <varpool_node> (node);
+      if (vnode && DECL_INITIAL (node->symbol.decl))
+	return vnode;
     }
   return NULL;
 }
@@ -846,9 +850,9 @@  varpool_next_static_initializer (struct
   symtab_node node1 = (symtab_node) node->symbol.next;
   for (; node1; node1 = node1->symbol.next)
     {
-      if (symtab_variable_p (node1)
-	  && DECL_INITIAL (node1->symbol.decl))
-	return varpool (node1);
+      varpool_node *vnode1 = dyn_cast <varpool_node> (node1);
+      if (vnode1 && DECL_INITIAL (node1->symbol.decl))
+	return vnode1;
     }
   return NULL;
 }
@@ -865,8 +869,9 @@  varpool_first_defined_variable (void)
   symtab_node node;
   for (node = symtab_nodes; node; node = node->symbol.next)
     {
-      if (symtab_variable_p (node) && varpool (node)->analyzed)
-	return varpool (node);
+      varpool_node *vnode = dyn_cast <varpool_node> (node);
+      if (vnode && vnode->analyzed)
+	return vnode;
     }
   return NULL;
 }
@@ -878,8 +883,9 @@  varpool_next_defined_variable (struct va
   symtab_node node1 = (symtab_node) node->symbol.next;
   for (; node1; node1 = node1->symbol.next)
     {
-      if (symtab_variable_p (node1) && varpool (node1)->analyzed)
-	return varpool (node1);
+      varpool_node *vnode1 = dyn_cast <varpool_node> (node1);
+      if (vnode1 && vnode1->analyzed)
+	return vnode1;
     }
   return NULL;
 }
@@ -895,8 +901,9 @@  cgraph_first_defined_function (void)
   symtab_node node;
   for (node = symtab_nodes; node; node = node->symbol.next)
     {
-      if (symtab_function_p (node) && cgraph (node)->analyzed)
-	return cgraph (node);
+      cgraph_node *cn = dyn_cast <cgraph_node> (node);
+      if (cn && cn->analyzed)
+	return cn;
     }
   return NULL;
 }
@@ -908,8 +915,9 @@  cgraph_next_defined_function (struct cgr
   symtab_node node1 = (symtab_node) node->symbol.next;
   for (; node1; node1 = node1->symbol.next)
     {
-      if (symtab_function_p (node1) && cgraph (node1)->analyzed)
-	return cgraph (node1);
+      cgraph_node *cn1 = dyn_cast <cgraph_node> (node1);
+      if (cn1 && cn1->analyzed)
+	return cn1;
     }
   return NULL;
 }
@@ -925,10 +933,8 @@  cgraph_first_function (void)
 {
   symtab_node node;
   for (node = symtab_nodes; node; node = node->symbol.next)
-    {
-      if (symtab_function_p (node))
-	return cgraph (node);
-    }
+    if (cgraph_node *cn = dyn_cast <cgraph_node> (node))
+      return cn;
   return NULL;
 }

@@ -938,10 +944,8 @@  cgraph_next_function (struct cgraph_node
 {
   symtab_node node1 = (symtab_node) node->symbol.next;
   for (; node1; node1 = node1->symbol.next)
-    {
-      if (symtab_function_p (node1))
-	return cgraph (node1);
-    }
+    if (cgraph_node *cn1 = dyn_cast <cgraph_node> (node1))
+      return cn1;
   return NULL;
 }
 /* Walk all functions.  */
@@ -968,9 +972,9 @@  cgraph_first_function_with_gimple_body (
   symtab_node node;
   for (node = symtab_nodes; node; node = node->symbol.next)
     {
-      if (symtab_function_p (node)
-	  && cgraph_function_with_gimple_body_p (cgraph (node)))
-	return cgraph (node);
+      cgraph_node *cn = dyn_cast <cgraph_node> (node);
+      if (cn && cgraph_function_with_gimple_body_p (cn))
+	return cn;
     }
   return NULL;
 }
@@ -982,9 +986,9 @@  cgraph_next_function_with_gimple_body (s
   symtab_node node1 = node->symbol.next;
   for (; node1; node1 = node1->symbol.next)
     {
-      if (symtab_function_p (node1)
-	  && cgraph_function_with_gimple_body_p (cgraph (node1)))
-	return cgraph (node1);
+      cgraph_node *cn1 = dyn_cast <cgraph_node> (node1);
+      if (cn1 && cgraph_function_with_gimple_body_p (cn1))
+	return cn1;
     }
   return NULL;
 }
@@ -1183,7 +1187,7 @@  cgraph_alias_aliased_node (struct cgraph

   ipa_ref_list_reference_iterate (&n->symbol.ref_list, 0, ref);
   gcc_checking_assert (ref->use == IPA_REF_ALIAS);
-  if (symtab_function_p (ref->referred))
+  if (is_a <cgraph_node> (ref->referred))
     return ipa_ref_node (ref);
   return NULL;
 }
@@ -1197,7 +1201,7 @@  varpool_alias_aliased_node (struct varpo

   ipa_ref_list_reference_iterate (&n->symbol.ref_list, 0, ref);
   gcc_checking_assert (ref->use == IPA_REF_ALIAS);
-  if (symtab_variable_p (ref->referred))
+  if (is_a <varpool_node> (ref->referred))
     return ipa_ref_varpool_node (ref);
   return NULL;
 }
@@ -1328,7 +1332,7 @@  symtab_real_symbol_p (symtab_node node)
   struct cgraph_node *cnode;
   struct ipa_ref *ref;

-  if (!symtab_function_p (node))
+  if (!is_a <cgraph_node> (node))
     return true;
   cnode = cgraph (node);
   if (cnode->global.inlined_to)
Index: gcc/tree-emutls.c
===================================================================
--- gcc/tree-emutls.c	(revision 192956)
+++ gcc/tree-emutls.c	(working copy)
@@ -260,7 +260,7 @@  get_emutls_init_templ_addr (tree decl)
   /* Create varpool node for the new variable and finalize it if it is
      not external one.  */
   if (DECL_EXTERNAL (to))
-    varpool_node (to);
+    varpool_node_for_decl (to);
   else
     varpool_add_new_variable (to);
   return build_fold_addr_expr (to);
@@ -332,7 +332,7 @@  new_emutls_decl (tree decl, tree alias_o
   /* Create varpool node for the new variable and finalize it if it is
      not external one.  */
   if (DECL_EXTERNAL (to))
-    varpool_node (to);
+    varpool_node_for_decl (to);
   else if (!alias_of)
     varpool_add_new_variable (to);
   else
Index: gcc/ipa-reference.c
===================================================================
--- gcc/ipa-reference.c	(revision 192956)
+++ gcc/ipa-reference.c	(working copy)
@@ -482,7 +482,7 @@  analyze_function (struct cgraph_node *fn
   local = init_function_info (fn);
   for (i = 0; ipa_ref_list_reference_iterate (&fn->symbol.ref_list,
i, ref); i++)
     {
-      if (!symtab_variable_p (ref->referred))
+      if (!is_a <varpool_node> (ref->referred))
 	continue;
       var = ipa_ref_varpool_node (ref)->symbol.decl;
       if (!is_proper_for_analysis (var))
@@ -979,8 +979,6 @@  stream_out_bitmap (struct lto_simple_out
 static void
 ipa_reference_write_optimization_summary (void)
 {
-  struct cgraph_node *node;
-  symtab_node snode;
   struct lto_simple_output_block *ob
     = lto_create_simple_output_block (LTO_section_ipa_reference);
   unsigned int count = 0;
@@ -994,12 +992,10 @@  ipa_reference_write_optimization_summary
   /* See what variables we are interested in.  */
   for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
     {
-      struct varpool_node *vnode;
-      snode = lto_symtab_encoder_deref (encoder, i);
-      if (!symtab_variable_p (snode))
-	continue;
-      vnode = varpool (snode);
-      if (bitmap_bit_p (all_module_statics, DECL_UID (vnode->symbol.decl))
+      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
+      varpool_node *vnode = dyn_cast <varpool_node> (snode);
+      if (vnode
+	  && bitmap_bit_p (all_module_statics, DECL_UID (vnode->symbol.decl))
 	  && referenced_from_this_partition_p (&vnode->symbol.ref_list, encoder))
 	{
 	  tree decl = vnode->symbol.decl;
@@ -1013,10 +1009,12 @@  ipa_reference_write_optimization_summary

   if (ltrans_statics_bitcount)
     for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
-      if (symtab_function_p (snode = lto_symtab_encoder_deref (encoder, i))
-	  && write_node_summary_p (cgraph (snode),
-				   encoder, ltrans_statics))
+      {
+	symtab_node snode = lto_symtab_encoder_deref (encoder, i);
+	cgraph_node *cnode = dyn_cast <cgraph_node> (snode);
+	if (cnode && write_node_summary_p (cnode, encoder, ltrans_statics))
 	  count++;
+      }

   streamer_write_uhwi_stream (ob->main_stream, count);
   if (count)
@@ -1027,17 +1025,15 @@  ipa_reference_write_optimization_summary
   if (ltrans_statics_bitcount)
     for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
       {
-	snode = lto_symtab_encoder_deref (encoder, i);
-	if (!symtab_function_p (snode))
-	  continue;
-	node = cgraph (snode);
-	if (write_node_summary_p (node, encoder, ltrans_statics))
+	symtab_node snode = lto_symtab_encoder_deref (encoder, i);
+	cgraph_node *cnode = dyn_cast <cgraph_node> (snode);
+	if (cnode && write_node_summary_p (cnode, encoder, ltrans_statics))
 	  {
 	    ipa_reference_optimization_summary_t info;
 	    int node_ref;

-	    info = get_reference_optimization_summary (node);
-	    node_ref = lto_symtab_encoder_encode (encoder, (symtab_node) node);
+	    info = get_reference_optimization_summary (cnode);
+	    node_ref = lto_symtab_encoder_encode (encoder, snode);
 	    streamer_write_uhwi_stream (ob->main_stream, node_ref);

 	    stream_out_bitmap (ob, info->statics_not_read, ltrans_statics,
Index: gcc/cgraphunit.c
===================================================================
--- gcc/cgraphunit.c	(revision 192956)
+++ gcc/cgraphunit.c	(working copy)
@@ -386,7 +386,8 @@  referred_to_p (symtab_node node)
   if (ipa_ref_list_referring_iterate (&node->symbol.ref_list, 0, ref))
     return true;
   /* For functions check also calls.  */
-  if (symtab_function_p (node) && cgraph (node)->callers)
+  cgraph_node *cn = dyn_cast <cgraph_node> (node);
+  if (cn && cn->callers)
     return true;
   return false;
 }
@@ -809,7 +810,7 @@  process_function_and_variable_attributes
 void
 varpool_finalize_decl (tree decl)
 {
-  struct varpool_node *node = varpool_node (decl);
+  struct varpool_node *node = varpool_node_for_decl (decl);

   gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl));

@@ -836,6 +837,35 @@  varpool_finalize_decl (tree decl)
     varpool_assemble_decl (node);
 }

+
+/* Determine if a symbol is finalized and needed.  */
+
+inline static bool
+symbol_finalized_and_needed (symtab_node node)
+{
+  if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
+    return cnode->local.finalized
+	   && cgraph_decide_is_function_needed (cnode, cnode->symbol.decl);
+  if (varpool_node *vnode = dyn_cast <varpool_node> (node))
+    return vnode->finalized
+	   && !DECL_EXTERNAL (vnode->symbol.decl)
+	   && decide_is_variable_needed (vnode, vnode->symbol.decl);
+  return false;
+}
+
+/* Determine if a symbol is finalized.  */
+
+inline static bool
+symbol_finalized (symtab_node node)
+{
+  if (cgraph_node *cnode= dyn_cast <cgraph_node> (node))
+    return cnode->local.finalized;
+  if (varpool_node *vnode = dyn_cast <varpool_node> (node))
+    return vnode->finalized;
+  return false;
+}
+
+
 /* Discover all functions and variables that are trivially needed, analyze
    them as well as all functions and variables referred by them  */

@@ -870,13 +900,7 @@  cgraph_analyze_functions (void)
 	   node != (symtab_node)first_analyzed
 	   && node != (symtab_node)first_analyzed_var; node = node->symbol.next)
 	{
-	  if ((symtab_function_p (node)
-	       && cgraph (node)->local.finalized
-	       && cgraph_decide_is_function_needed (cgraph (node), node->symbol.decl))
-	      || (symtab_variable_p (node)
-		  && varpool (node)->finalized
-		  && !DECL_EXTERNAL (node->symbol.decl)
-		  && decide_is_variable_needed (varpool (node), node->symbol.decl)))
+	  if (symbol_finalized_and_needed (node))
 	    {
 	      enqueue_node (node);
 	      if (!changed && cgraph_dump_file)
@@ -903,18 +927,15 @@  cgraph_analyze_functions (void)
 	  changed = true;
 	  node = first;
 	  first = (symtab_node)first->symbol.aux;
-	  if (symtab_function_p (node) && cgraph (node)->local.finalized)
+	  cgraph_node *cnode = dyn_cast <cgraph_node> (node);
+	  if (cnode && cnode->local.finalized)
 	    {
 	      struct cgraph_edge *edge;
-	      struct cgraph_node *cnode;
-	      tree decl;
-
-	      cnode = cgraph (node);
-	      decl = cnode->symbol.decl;
+	      tree decl = cnode->symbol.decl;

-	      /* ??? It is possible to create extern inline function and later using
-		 weak alias attribute to kill its body. See
-		 gcc.c-torture/compile/20011119-1.c  */
+	      /* ??? It is possible to create extern inline function
+	      and later using weak alias attribute to kill its body.
+	      See gcc.c-torture/compile/20011119-1.c  */
 	      if (!DECL_STRUCT_FUNCTION (decl)
 		  && (!cnode->alias || !cnode->thunk.alias)
 		  && !cnode->thunk.thunk_p)
@@ -929,23 +950,25 @@  cgraph_analyze_functions (void)

 	      for (edge = cnode->callees; edge; edge = edge->next_callee)
 		if (edge->callee->local.finalized)
-		  enqueue_node ((symtab_node)edge->callee);
+		   enqueue_node ((symtab_node)edge->callee);

-	      /* If decl is a clone of an abstract function, mark that abstract
-		 function so that we don't release its body. The DECL_INITIAL() of that
-		 abstract function declaration will be later needed to output debug
-		 info.  */
+	      /* If decl is a clone of an abstract function,
+	      mark that abstract function so that we don't release its body.
+	      The DECL_INITIAL() of that abstract function declaration
+	      will be later needed to output debug info.  */
 	      if (DECL_ABSTRACT_ORIGIN (decl))
 		{
-		  struct cgraph_node *origin_node;
-		  origin_node = cgraph_get_node (DECL_ABSTRACT_ORIGIN (decl));
+		  struct cgraph_node *origin_node
+	    	  = cgraph_get_node (DECL_ABSTRACT_ORIGIN (decl));
 		  origin_node->abstract_and_needed = true;
 		}
-
 	    }
-	  else if (symtab_variable_p (node)
-		   && varpool (node)->finalized)
-	    varpool_analyze_node (varpool (node));
+	  else
+	    {
+	      varpool_node *vnode = dyn_cast <varpool_node> (node);
+	      if (vnode && vnode->finalized)
+		varpool_analyze_node (vnode);
+	    }

 	  if (node->symbol.same_comdat_group)
 	    {
@@ -956,8 +979,7 @@  cgraph_analyze_functions (void)
 		enqueue_node (next);
 	    }
 	  for (i = 0; ipa_ref_list_reference_iterate
(&node->symbol.ref_list, i, ref); i++)
-	    if ((symtab_function_p (ref->referred) && cgraph
(ref->referred)->local.finalized)
-		|| (symtab_variable_p (ref->referred) && varpool (ref->referred)->finalized))
+	    if (symbol_finalized (ref->referred))
 	      enqueue_node (ref->referred);
           cgraph_process_new_functions ();
 	}
@@ -985,10 +1007,9 @@  cgraph_analyze_functions (void)
 	  symtab_remove_node (node);
 	  continue;
 	}
-      if (symtab_function_p (node))
+      if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
 	{
 	  tree decl = node->symbol.decl;
-	  struct cgraph_node *cnode = cgraph (node);

 	  if (cnode->local.finalized && !gimple_has_body_p (decl)
 	      && (!cnode->alias || !cnode->thunk.alias)
@@ -1070,7 +1091,7 @@  handle_alias_pairs (void)
 	}

       if (TREE_CODE (p->decl) == FUNCTION_DECL
-          && target_node && symtab_function_p (target_node))
+          && target_node && is_a <cgraph_node> (target_node))
 	{
 	  struct cgraph_node *src_node = cgraph_get_node (p->decl);
 	  if (src_node && src_node->local.finalized)
@@ -1079,7 +1100,7 @@  handle_alias_pairs (void)
 	  VEC_unordered_remove (alias_pair, alias_pairs, i);
 	}
       else if (TREE_CODE (p->decl) == VAR_DECL
-	       && target_node && symtab_variable_p (target_node))
+	       && target_node && is_a <varpool_node> (target_node))
 	{
 	  varpool_create_variable_alias (p->decl, target_node->symbol.decl);
 	  VEC_unordered_remove (alias_pair, alias_pairs, i);
Index: gcc/cp/decl2.c
===================================================================
--- gcc/cp/decl2.c	(revision 192956)
+++ gcc/cp/decl2.c	(working copy)
@@ -1775,7 +1775,7 @@  import_export_class (tree ctype)
 static bool
 var_finalized_p (tree var)
 {
-  return varpool_node (var)->finalized;
+  return varpool_node_for_decl (var)->finalized;
 }

 /* DECL is a VAR_DECL or FUNCTION_DECL which, for whatever reason,
@@ -1893,7 +1893,7 @@  maybe_emit_vtables (tree ctype)
 	TREE_ASM_WRITTEN (vtbl) = 1;
       else if (DECL_ONE_ONLY (vtbl))
 	{
-	  current = varpool_node (vtbl);
+	  current = varpool_node_for_decl (vtbl);
 	  if (last)
 	    symtab_add_to_same_comdat_group ((symtab_node) current,
(symtab_node) last);
 	  last = current;
Index: gcc/ipa-ref.c
===================================================================
--- gcc/ipa-ref.c	(revision 192956)
+++ gcc/ipa-ref.c	(working copy)
@@ -42,7 +42,7 @@  ipa_record_reference (symtab_node referr
   struct ipa_ref_list *list, *list2;
   VEC(ipa_ref_t,gc) *old_references;

-  gcc_checking_assert (!stmt || symtab_function_p (referring_node));
+  gcc_checking_assert (!stmt || is_a <cgraph_node> (referring_node));
   gcc_checking_assert (use_type != IPA_REF_ALIAS || !stmt);

   list = &referring_node->symbol.ref_list;
Index: gcc/lto-cgraph.c
===================================================================
--- gcc/lto-cgraph.c	(revision 192956)
+++ gcc/lto-cgraph.c	(working copy)
@@ -679,7 +679,7 @@  add_references (lto_symtab_encoder_t enc
   int i;
   struct ipa_ref *ref;
   for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++)
-    if (symtab_function_p (ref->referred))
+    if (is_a <cgraph_node> (ref->referred))
       add_node_to (encoder, ipa_ref_node (ref), false);
     else
       lto_symtab_encoder_encode (encoder, ref->referred);
@@ -730,9 +730,8 @@  compute_ltrans_boundary (lto_symtab_enco
   for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
     {
       symtab_node node = lto_symtab_encoder_deref (encoder, i);
-      if (symtab_variable_p (node))
+      if (varpool_node *vnode = dyn_cast <varpool_node> (node))
 	{
-	  struct varpool_node *vnode = varpool (node);
 	  if (DECL_INITIAL (vnode->symbol.decl)
 	      && !lto_symtab_encoder_encode_initializer_p (encoder,
 							   vnode)
@@ -796,8 +795,8 @@  output_symtab (void)
   for (i = 0; i < n_nodes; i++)
     {
       symtab_node node = lto_symtab_encoder_deref (encoder, i);
-      if (symtab_function_p (node))
-        lto_output_node (ob, cgraph (node), encoder);
+      if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
+        lto_output_node (ob, cnode, encoder);
       else
         lto_output_varpool_node (ob, varpool (node), encoder);
 	
@@ -983,7 +982,7 @@  input_varpool_node (struct lto_file_decl
   order = streamer_read_hwi (ib) + order_base;
   decl_index = streamer_read_uhwi (ib);
   var_decl = lto_file_decl_data_get_var_decl (file_data, decl_index);
-  node = varpool_node (var_decl);
+  node = varpool_node_for_decl (var_decl);
   node->symbol.order = order;
   if (order >= symtab_order)
     symtab_order = order + 1;
@@ -1144,14 +1143,14 @@  input_cgraph_1 (struct lto_file_decl_dat
   /* AUX pointers should be all non-zero for function nodes read from
the stream.  */
 #ifdef ENABLE_CHECKING
   FOR_EACH_VEC_ELT (symtab_node, nodes, i, node)
-    gcc_assert (node->symbol.aux || !symtab_function_p (node));
+    gcc_assert (node->symbol.aux || !is_a <cgraph_node> (node));
 #endif
   FOR_EACH_VEC_ELT (symtab_node, nodes, i, node)
     {
       int ref;
-      if (symtab_function_p (node))
+      if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
 	{
-	  ref = (int) (intptr_t) cgraph (node)->global.inlined_to;
+	  ref = (int) (intptr_t) cnode->global.inlined_to;

 	  /* We share declaration of builtins, so we may read same node twice.  */
 	  if (!node->symbol.aux)
@@ -1160,9 +1159,9 @@  input_cgraph_1 (struct lto_file_decl_dat

 	  /* Fixup inlined_to from reference to pointer.  */
 	  if (ref != LCC_NOT_FOUND)
-	    cgraph (node)->global.inlined_to = cgraph (VEC_index
(symtab_node, nodes, ref));
+	    cnode->global.inlined_to = cgraph (VEC_index (symtab_node, nodes, ref));
 	  else
-	    cgraph (node)->global.inlined_to = NULL;
+	    cnode->global.inlined_to = NULL;
 	}

       ref = (int) (intptr_t) node->symbol.same_comdat_group;
@@ -1174,7 +1173,7 @@  input_cgraph_1 (struct lto_file_decl_dat
 	node->symbol.same_comdat_group = NULL;
     }
   FOR_EACH_VEC_ELT (symtab_node, nodes, i, node)
-    node->symbol.aux = symtab_function_p (node) ? (void *)1 : NULL;
+    node->symbol.aux = is_a <cgraph_node> (node) ? (void *)1 : NULL;
   return nodes;
 }

@@ -1449,7 +1448,6 @@  output_node_opt_summary (struct output_b
 static void
 output_cgraph_opt_summary (void)
 {
-  symtab_node node;
   int i, n_nodes;
   lto_symtab_encoder_t encoder;
   struct output_block *ob = create_output_block (LTO_section_cgraph_opt_sum);
@@ -1459,18 +1457,21 @@  output_cgraph_opt_summary (void)
   encoder = ob->decl_state->symtab_node_encoder;
   n_nodes = lto_symtab_encoder_size (encoder);
   for (i = 0; i < n_nodes; i++)
-    if (symtab_function_p (node = lto_symtab_encoder_deref (encoder, i))
-	&& output_cgraph_opt_summary_p (cgraph (node)))
-      count++;
+    {
+      symtab_node node = lto_symtab_encoder_deref (encoder, i);
+      cgraph_node *cnode = dyn_cast <cgraph_node> (node);
+      if (cnode && output_cgraph_opt_summary_p (cnode))
+	count++;
+    }
   streamer_write_uhwi (ob, count);
   for (i = 0; i < n_nodes; i++)
     {
-      node = lto_symtab_encoder_deref (encoder, i);
-      if (symtab_function_p (node)
-	  && output_cgraph_opt_summary_p (cgraph (node)))
+      symtab_node node = lto_symtab_encoder_deref (encoder, i);
+      cgraph_node *cnode = dyn_cast <cgraph_node> (node);
+      if (cnode && output_cgraph_opt_summary_p (cnode))
 	{
 	  streamer_write_uhwi (ob, i);
-	  output_node_opt_summary (ob, cgraph (node), encoder);
+	  output_node_opt_summary (ob, cnode, encoder);
 	}
     }
   produce_asm (ob, NULL);
Index: gcc/lto-streamer-out.c
===================================================================
--- gcc/lto-streamer-out.c	(revision 192956)
+++ gcc/lto-streamer-out.c	(working copy)
@@ -956,7 +956,6 @@  copy_function (struct cgraph_node *node)
 static void
 lto_output (void)
 {
-  struct cgraph_node *node;
   struct lto_out_decl_state *decl_state;
 #ifdef ENABLE_CHECKING
   bitmap output = lto_bitmap_alloc ();
@@ -972,10 +971,9 @@  lto_output (void)
   for (i = 0; i < n_nodes; i++)
     {
       symtab_node snode = lto_symtab_encoder_deref (encoder, i);
-      if (!symtab_function_p (snode))
-	continue;
-      node = cgraph (snode);
-      if (lto_symtab_encoder_encode_body_p (encoder, node)
+      cgraph_node *node = dyn_cast <cgraph_node> (snode);
+      if (node
+	  && lto_symtab_encoder_encode_body_p (encoder, node)
 	  && !node->alias
 	  && !node->thunk.thunk_p)
 	{
Index: gcc/ada/gcc-interface/utils.c
===================================================================
--- gcc/ada/gcc-interface/utils.c	(revision 192956)
+++ gcc/ada/gcc-interface/utils.c	(working copy)
@@ -5586,7 +5586,7 @@  gnat_write_global_declarations (void)
 		      void_type_node);
       TREE_STATIC (dummy_global) = 1;
       TREE_ASM_WRITTEN (dummy_global) = 1;
-      node = varpool_node (dummy_global);
+      node = varpool_node_for_decl (dummy_global);
       node->symbol.force_output = 1;

       while (!VEC_empty (tree, types_used_by_cur_var_decl))
Index: gcc/ipa.c
===================================================================
--- gcc/ipa.c	(revision 192956)
+++ gcc/ipa.c	(working copy)
@@ -84,7 +84,7 @@  process_references (struct ipa_ref_list
   struct ipa_ref *ref;
   for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++)
     {
-      if (symtab_function_p (ref->referred))
+      if (is_a <cgraph_node> (ref->referred))
 	{
 	  struct cgraph_node *node = ipa_ref_node (ref);

@@ -290,10 +290,8 @@  symtab_remove_unreachable_nodes (bool be
 			      before_inlining_p, reachable);
 	}

-      if (symtab_function_p (node))
+      if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
 	{
-	  struct cgraph_node *cnode = cgraph (node);
-
 	  /* Mark the callees reachable unless they are direct calls to extern
  	     inline functions we decided to not inline.  */
 	  if (!in_boundary_p)
@@ -332,18 +330,18 @@  symtab_remove_unreachable_nodes (bool be
 	    }
 	}
       /* When we see constructor of external variable, keep referred
nodes in the
-	 boundary.  This will also hold initializers of the external vars NODE
-	 reffers to.  */
-      if (symtab_variable_p (node)
+	boundary.  This will also hold initializers of the external vars NODE
+	refers to.  */
+      varpool_node *vnode = dyn_cast <varpool_node> (node);
+      if (vnode
 	  && DECL_EXTERNAL (node->symbol.decl)
-	  && !varpool (node)->alias
+	  && !vnode->alias
 	  && in_boundary_p)
-        {
-	  int i;
+	{
 	  struct ipa_ref *ref;
-	  for (i = 0; ipa_ref_list_reference_iterate
(&node->symbol.ref_list, i, ref); i++)
+	  for (int i = 0; ipa_ref_list_reference_iterate
(&node->symbol.ref_list, i, ref); i++)
 	    enqueue_node (ref->referred, &first, reachable);
-        }
+	}
     }

   /* Remove unreachable functions.   */
@@ -526,7 +524,7 @@  cgraph_address_taken_from_non_vtable_p (
     if (ref->use == IPA_REF_ADDR)
       {
 	struct varpool_node *node;
-	if (symtab_function_p (ref->referring))
+	if (is_a <cgraph_node> (ref->referring))
 	  return true;
 	node = ipa_ref_referring_varpool_node (ref);
 	if (!DECL_VIRTUAL_P (node->symbol.decl))
Index: gcc/ipa-inline-analysis.c
===================================================================
--- gcc/ipa-inline-analysis.c	(revision 192956)
+++ gcc/ipa-inline-analysis.c	(working copy)
@@ -3855,22 +3855,25 @@  void
 inline_write_summary (void)
 {
   struct cgraph_node *node;
-  symtab_node snode;
   struct output_block *ob = create_output_block (LTO_section_inline_summary);
   lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
   unsigned int count = 0;
   int i;

   for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
-    if (symtab_function_p (snode = lto_symtab_encoder_deref (encoder, i))
-	&& cgraph (snode)->analyzed)
-      count++;
+    {
+      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
+      cgraph_node *cnode = dyn_cast <cgraph_node> (snode);
+      if (cnode && cnode->analyzed)
+	count++;
+    }
   streamer_write_uhwi (ob, count);

   for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
     {
-      if (symtab_function_p (snode = lto_symtab_encoder_deref (encoder, i))
-	  && (node = cgraph (snode))->analyzed)
+      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
+      cgraph_node *cnode = dyn_cast <cgraph_node> (snode);
+      if (cnode && (node = cnode)->analyzed)
 	{
 	  struct inline_summary *info = inline_summary (node);
 	  struct bitpack_d bp;
@@ -3878,7 +3881,7 @@  inline_write_summary (void)
 	  int i;
 	  size_time_entry *e;
 	  struct condition *c;
-
+
 	  streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder,
(symtab_node)node));
 	  streamer_write_hwi (ob, info->estimated_self_stack_size);
 	  streamer_write_hwi (ob, info->self_size);
@@ -3897,7 +3900,7 @@  inline_write_summary (void)
 	      bp_pack_value (&bp, c->by_ref, 1);
 	      streamer_write_bitpack (&bp);
 	      if (c->agg_contents)
-		streamer_write_uhwi (ob, c->offset);
+	        streamer_write_uhwi (ob, c->offset);
 	    }
 	  streamer_write_uhwi (ob, VEC_length (size_time_entry, info->entry));
 	  for (i = 0;
Index: gcc/lto/lto.c
===================================================================
--- gcc/lto/lto.c	(revision 192956)
+++ gcc/lto/lto.c	(working copy)
@@ -2671,12 +2671,17 @@  lto_wpa_write_files (void)
 	      if (!lto_symtab_encoder_in_partition_p (part->encoder, node))
 		{
 	          fprintf (cgraph_dump_file, "%s ", symtab_node_asm_name (node));
-		  if (symtab_function_p (node)
-		      && lto_symtab_encoder_encode_body_p (part->encoder, cgraph (node)))
+		  cgraph_node *cnode = dyn_cast <cgraph_node> (node);
+		  if (cnode
+		      && lto_symtab_encoder_encode_body_p (part->encoder, cnode))
 		    fprintf (cgraph_dump_file, "(body included)");
-		  else if (symtab_variable_p (node)
-		           && lto_symtab_encoder_encode_initializer_p
(part->encoder, varpool (node)))
-		    fprintf (cgraph_dump_file, "(initializer included)");
+		  else
+		    {
+		      varpool_node *vnode = dyn_cast <varpool_node> (node);
+		      if (vnode
+			  && lto_symtab_encoder_encode_initializer_p (part->encoder, vnode))
+			fprintf (cgraph_dump_file, "(initializer included)");
+		    }
 		}
 	    }
 	  fprintf (cgraph_dump_file, "\n");
Index: gcc/lto/lto-partition.c
===================================================================
--- gcc/lto/lto-partition.c	(revision 192956)
+++ gcc/lto/lto-partition.c	(working copy)
@@ -55,22 +55,22 @@  get_symbol_class (symtab_node node)
 {
   /* Inline clones are always duplicated.
      This include external delcarations.   */
-  if (symtab_function_p (node)
-      && cgraph (node)->global.inlined_to)
+  cgraph_node *cnode = dyn_cast <cgraph_node> (node);
+  if (cnode && cnode->global.inlined_to)
     return SYMBOL_DUPLICATE;

   /* External declarations are external.  */
   if (DECL_EXTERNAL (node->symbol.decl))
     return SYMBOL_EXTERNAL;

-  if (symtab_variable_p (node))
+  if (varpool_node *vnode = dyn_cast <varpool_node> (node))
     {
       /* Constant pool references use local symbol names that can not
          be promoted global.  We should never put into a constant pool
          objects that can not be duplicated across partitions.  */
       if (DECL_IN_CONSTANT_POOL (node->symbol.decl))
 	return SYMBOL_DUPLICATE;
-      gcc_checking_assert (varpool (node)->analyzed);
+      gcc_checking_assert (vnode->analyzed);
     }
   /* Functions that are cloned may stay in callgraph even if they are unused.
      Handle them as external; compute_ltrans_boundary take care to make
@@ -145,7 +145,7 @@  add_references_to_partition (ltrans_part
     /* References to a readonly variable may be constant foled into its value.
        Recursively look into the initializers of the constant variable and add
        references, too.  */
-    else if (symtab_variable_p (ref->referred)
+    else if (is_a <varpool_node> (ref->referred)
 	     && const_value_known_p (ref->referred->symbol.decl)
 	     && !lto_symtab_encoder_in_partition_p (part->encoder, ref->referred))
       {
@@ -196,9 +196,8 @@  add_symbol_to_partition_1 (ltrans_partit
     }
   node->symbol.aux = (void *)((size_t)node->symbol.aux + 1);

-  if (symtab_function_p (node))
+  if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
     {
-      struct cgraph_node *cnode = cgraph (node);
       struct cgraph_edge *e;
       part->insns += inline_summary (cnode)->self_size;

@@ -247,15 +246,15 @@  contained_in_symbol (symtab_node node)
   if (lookup_attribute ("weakref",
 			DECL_ATTRIBUTES (node->symbol.decl)))
     return node;
-  if (symtab_function_p (node))
+  if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
     {
-      struct cgraph_node *cnode = cgraph_function_node (cgraph (node), NULL);
+      cnode = cgraph_function_node (cnode, NULL);
       if (cnode->global.inlined_to)
 	cnode = cnode->global.inlined_to;
       return (symtab_node) cnode;
     }
-  else if (symtab_variable_p (node))
-    return (symtab_node) varpool_variable_node (varpool (node), NULL);
+  else if (varpool_node *vnode = dyn_cast <varpool_node> (node))
+    return (symtab_node) varpool_variable_node (vnode, NULL);
   return node;
 }

@@ -302,8 +301,8 @@  undo_partition (ltrans_partition partiti
 	pointer_set_destroy (partition->initializers_visited);
       partition->initializers_visited = NULL;

-      if (symtab_function_p (node))
-        partition->insns -= inline_summary (cgraph (node))->self_size;
+      if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
+        partition->insns -= inline_summary (cnode)->self_size;
       lto_symtab_encoder_delete_node (partition->encoder, node);
       node->symbol.aux = (void *)((size_t)node->symbol.aux - 1);
     }
@@ -555,11 +554,10 @@  lto_balanced_map (void)
 	  symtab_node snode = lto_symtab_encoder_deref (partition->encoder,
 							last_visited_node);

-	  if (symtab_function_p (snode))
+	  if (cgraph_node *node = dyn_cast <cgraph_node> (snode))
 	    {
 	      struct cgraph_edge *edge;

-	      node = cgraph (snode);
 	      refs = &node->symbol.ref_list;

 	      last_visited_node++;
@@ -611,7 +609,7 @@  lto_balanced_map (void)
 	  /* Compute boundary cost of IPA REF edges and at the same time look into
 	     variables referenced from current partition and try to add them.  */
 	  for (j = 0; ipa_ref_list_reference_iterate (refs, j, ref); j++)
-	    if (symtab_variable_p (ref->referred))
+	    if (is_a <varpool_node> (ref->referred))
 	      {
 		int index;

@@ -645,7 +643,7 @@  lto_balanced_map (void)
 		  cost++;
 	      }
 	  for (j = 0; ipa_ref_list_referring_iterate (refs, j, ref); j++)
-	    if (symtab_variable_p (ref->referring))
+	    if (is_a <varpool_node> (ref->referring))
 	      {
 		int index;

Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c	(revision 192956)
+++ gcc/varasm.c	(working copy)
@@ -2221,7 +2221,7 @@  mark_decl_referenced (tree decl)
     }
   else if (TREE_CODE (decl) == VAR_DECL)
     {
-      struct varpool_node *node = varpool_node (decl);
+      struct varpool_node *node = varpool_node_for_decl (decl);
       /* C++ frontend use mark_decl_references to force COMDAT variables
          to be output that might appear dead otherwise.  */
       node->symbol.force_output = true;
@@ -5549,7 +5549,7 @@  assemble_alias (tree decl, tree target)
   if (TREE_CODE (decl) == FUNCTION_DECL)
     cgraph_get_create_node (decl)->alias = true;
   else
-    varpool_node (decl)->alias = true;
+    varpool_node_for_decl (decl)->alias = true;

   /* If the target has already been emitted, we don't have to queue the
      alias.  This saves a tad of memory.  */
Index: gcc/symtab.c
===================================================================
--- gcc/symtab.c	(revision 192956)
+++ gcc/symtab.c	(working copy)
@@ -104,7 +104,7 @@  eq_assembler_name (const void *p1, const
 static void
 insert_to_assembler_name_hash (symtab_node node)
 {
-  if (symtab_variable_p (node) && DECL_HARD_REGISTER (node->symbol.decl))
+  if (is_a <varpool_node> (node) && DECL_HARD_REGISTER (node->symbol.decl))
     return;
   gcc_checking_assert (!node->symbol.previous_sharing_asm_name
 		       && !node->symbol.next_sharing_asm_name);
@@ -252,8 +252,8 @@  symtab_unregister_node (symtab_node node
   if (*slot == node)
     {
       symtab_node replacement_node = NULL;
-      if (symtab_function_p (node))
-	replacement_node = (symtab_node)cgraph_find_replacement_node (cgraph (node));
+      if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
+	replacement_node = (symtab_node)cgraph_find_replacement_node (cnode);
       if (!replacement_node)
 	htab_clear_slot (symtab_hash, slot);
       else
@@ -294,10 +294,10 @@  symtab_get_node (const_tree decl)
 void
 symtab_remove_node (symtab_node node)
 {
-  if (symtab_function_p (node))
-    cgraph_remove_node (cgraph (node));
-  else if (symtab_variable_p (node))
-    varpool_remove_node (varpool (node));
+  if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
+    cgraph_remove_node (cnode);
+  else if (varpool_node *vnode = dyn_cast <varpool_node> (node))
+    varpool_remove_node (vnode);
 }

 /* Initalize asm name hash unless.  */
@@ -538,10 +538,10 @@  dump_symtab_base (FILE *f, symtab_node n
 void
 dump_symtab_node (FILE *f, symtab_node node)
 {
-  if (symtab_function_p (node))
-    dump_cgraph_node (f, cgraph (node));
-  else if (symtab_variable_p (node))
-    dump_varpool_node (f, varpool (node));
+  if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
+    dump_cgraph_node (f, cnode);
+  else if (varpool_node *vnode = dyn_cast <varpool_node> (node))
+    dump_varpool_node (f, vnode);
 }

 /* Dump symbol table.  */
@@ -579,7 +579,7 @@  verify_symtab_base (symtab_node node)
   bool error_found = false;
   symtab_node hashed_node;

-  if (symtab_function_p (node))
+  if (is_a <cgraph_node> (node))
     {
       if (TREE_CODE (node->symbol.decl) != FUNCTION_DECL)
 	{
@@ -587,7 +587,7 @@  verify_symtab_base (symtab_node node)
           error_found = true;
 	}
     }
-  else if (symtab_variable_p (node))
+  else if (is_a <varpool_node> (node))
     {
       if (TREE_CODE (node->symbol.decl) != VAR_DECL)
 	{
@@ -622,7 +622,8 @@  verify_symtab_base (symtab_node node)
 	  hashed_node = hashed_node->symbol.next_sharing_asm_name;
 	}
       if (!hashed_node
-          && !(symtab_variable_p (node) || DECL_HARD_REGISTER
(node->symbol.decl)))
+          && !(is_a <varpool_node> (node)
+	       || DECL_HARD_REGISTER (node->symbol.decl)))
 	{
           error ("node not found in symtab assembler name hash");
           error_found = true;
@@ -676,8 +677,8 @@  verify_symtab_node (symtab_node node)
     return;

   timevar_push (TV_CGRAPH_VERIFY);
-  if (symtab_function_p (node))
-    verify_cgraph_node (cgraph (node));
+  if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
+    verify_cgraph_node (cnode);
   else
     if (verify_symtab_base (node))
       {
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 192956)
+++ gcc/Makefile.in	(working copy)
@@ -886,7 +886,7 @@  CFGLOOP_H = cfgloop.h $(BASIC_BLOCK_H) v
 IPA_UTILS_H = ipa-utils.h $(TREE_H) $(CGRAPH_H)
 IPA_REFERENCE_H = ipa-reference.h $(BITMAP_H) $(TREE_H)
 CGRAPH_H = cgraph.h $(VEC_H) $(TREE_H) $(BASIC_BLOCK_H) $(FUNCTION_H) \
-	cif-code.def ipa-ref.h ipa-ref-inline.h $(LINKER_PLUGIN_API_H)
+	cif-code.def ipa-ref.h ipa-ref-inline.h $(LINKER_PLUGIN_API_H) is-a.h
 DF_H = df.h $(BITMAP_H) $(REGSET_H) sbitmap.h $(BASIC_BLOCK_H) \
 	alloc-pool.h $(TIMEVAR_H)
 VALTRACK_H = valtrack.h $(BITMAP_H) $(DF_H) $(RTL_H) $(BASIC_BLOCK_H) \
Index: gcc/passes.c
===================================================================
--- gcc/passes.c	(revision 192956)
+++ gcc/passes.c	(working copy)
@@ -201,7 +201,7 @@  rest_of_decl_compilation (tree decl,
     ;
   else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)
 	   && TREE_STATIC (decl))
-    varpool_node (decl);
+    varpool_node_for_decl (decl);
 }

 /* Called after finishing a record, union or enumeral type.  */
Index: gcc/varpool.c
===================================================================
--- gcc/varpool.c	(revision 192956)
+++ gcc/varpool.c	(working copy)
@@ -39,7 +39,7 @@  along with GCC; see the file COPYING3.

 /* Return varpool node assigned to DECL.  Create new one when needed.  */
 struct varpool_node *
-varpool_node (tree decl)
+varpool_node_for_decl (tree decl)
 {
   struct varpool_node *node = varpool_get_node (decl);
   gcc_assert (TREE_CODE (decl) == VAR_DECL
@@ -114,9 +114,9 @@  debug_varpool (void)
 struct varpool_node *
 varpool_node_for_asm (tree asmname)
 {
-  symtab_node node = symtab_node_for_asm (asmname);
-  if (node && symtab_variable_p (node))
-    return varpool (node);
+  if (symtab_node node = symtab_node_for_asm (asmname))
+    if (varpool_node *vnode = dyn_cast <varpool_node> (node))
+      return vnode;
   return NULL;
 }

@@ -192,7 +192,7 @@  varpool_add_new_variable (tree decl)
 {
   struct varpool_node *node;
   varpool_finalize_decl (decl);
-  node = varpool_node (decl);
+  node = varpool_node_for_decl (decl);
   if (varpool_externally_visible_p (node, false))
     node->symbol.externally_visible = true;
 }
@@ -232,7 +232,7 @@  varpool_analyze_node (struct varpool_nod
     }
   if (node->alias && node->alias_of)
     {
-      struct varpool_node *tgt = varpool_node (node->alias_of);
+      struct varpool_node *tgt = varpool_node_for_decl (node->alias_of);
       struct varpool_node *n;

       for (n = tgt; n && n->alias;
@@ -378,16 +378,21 @@  varpool_remove_unreferenced_decls (void)
 	  for (next = node->symbol.same_comdat_group;
 	       next != (symtab_node)node;
 	       next = next->symbol.same_comdat_group)
-	    if (symtab_variable_p (next)
-		&& varpool (next)->analyzed)
-	      enqueue_node (varpool (next), &first);
+	    {
+	      varpool_node *vnext = dyn_cast <varpool_node> (next);
+	      if (vnext && vnext->analyzed)
+		enqueue_node (vnext, &first);
+	    }
 	}
       for (i = 0; ipa_ref_list_reference_iterate
(&node->symbol.ref_list, i, ref); i++)
-	if (symtab_variable_p (ref->referred)
-	    && (!DECL_EXTERNAL (ref->referred->symbol.decl)
-		|| varpool (ref->referred)->alias)
-	    && varpool (ref->referred)->analyzed)
-	  enqueue_node (varpool (ref->referred), &first);
+	{
+	  varpool_node *vnode = dyn_cast <varpool_node> (ref->referred);
+	  if (vnode
+	      && (!DECL_EXTERNAL (ref->referred->symbol.decl)
+		  || vnode->alias)
+	      && vnode->analyzed)
+	    enqueue_node (vnode, &first);
+	}
     }
   if (cgraph_dump_file)
     fprintf (cgraph_dump_file, "\nRemoving variables:");
@@ -461,7 +466,7 @@  add_new_static_var (tree type)
   DECL_CONTEXT (new_decl) = NULL_TREE;
   DECL_ABSTRACT (new_decl) = 0;
   lang_hooks.dup_lang_specific_decl (new_decl);
-  new_node = varpool_node (new_decl);
+  new_node = varpool_node_for_decl (new_decl);
   varpool_finalize_decl (new_decl);

   return new_node->symbol.decl;
@@ -477,7 +482,7 @@  varpool_create_variable_alias (tree alia

   gcc_assert (TREE_CODE (decl) == VAR_DECL);
   gcc_assert (TREE_CODE (alias) == VAR_DECL);
-  alias_node = varpool_node (alias);
+  alias_node = varpool_node_for_decl (alias);
   alias_node->alias = 1;
   alias_node->finalized = 1;
   alias_node->alias_of = decl;
Index: gcc/lto-streamer.h
===================================================================
--- gcc/lto-streamer.h	(revision 192956)
+++ gcc/lto-streamer.h	(working copy)
@@ -1115,7 +1115,7 @@  lsei_next_function_in_partition (lto_sym
 {
   lsei_next (lsei);
   while (!lsei_end_p (*lsei)
-	 && (!symtab_function_p (lsei_node (*lsei))
+	 && (!is_a <cgraph_node> (lsei_node (*lsei))
 	     || !lto_symtab_encoder_in_partition_p (lsei->encoder, lsei_node
(*lsei))))
     lsei_next (lsei);