Patchwork Use conditional casting with symtab_node

login
register
mail settings
Submitter Lawrence Crowl
Date Sept. 18, 2012, 6:01 p.m.
Message ID <CAGqM8fZ2YneGzYCzTtVusOiN1CtZMxfGt1FQe7WrhzdjgKUr1w@mail.gmail.com>
Download mbox | patch
Permalink /patch/184790/
State New
Headers show

Comments

Lawrence Crowl - Sept. 18, 2012, 6:01 p.m.
Add functions symtab_node_def::try_function and symtab_node_def::try_variable.
These function return a pointer to the more specific type (e.g. cgraph_node*)
if and only if the general type (symtab_node aka symtab_node_def*) is an
instance of the specific type.  These functions are essentially checked down
casts.

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 = node->try_function ())
    {
      ....
    }

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, a little
restructuring is required to pull out the secondary conditions.  For example,

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

becomes

  if (varpool_node *vnode = node->try_variable ())
    if (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 member functions symtab_node_def::is_function and
symtab_node_def::is_variable.  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_tree.


The new code bootstraps .616% faster with a 99% confidence of being faster.


Tested on x86_64.


Okay for trunk?


 }
@@ -1134,7 +1134,7 @@ lsei_start_function_in_partition (lto_sy

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

@@ -1147,7 +1147,7 @@ lsei_next_variable_in_partition (lto_sym
 {
   lsei_next (lsei);
   while (!lsei_end_p (*lsei)
-	 && (!symtab_variable_p (lsei_node (*lsei))
+	 && (!lsei_node (*lsei)->is_variable ()
 	     || !lto_symtab_encoder_in_partition_p (lsei->encoder, lsei_node
(*lsei))))
     lsei_next (lsei);
 }
@@ -1160,7 +1160,7 @@ lsei_start_variable_in_partition (lto_sy

   if (lsei_end_p (lsei))
     return lsei;
-  if (!symtab_variable_p (lsei_node (lsei))
+  if (!lsei_node (lsei)->is_variable ()
       || !lto_symtab_encoder_in_partition_p (encoder, lsei_node (lsei)))
     lsei_next_variable_in_partition (&lsei);
Eric Botcazou - Sept. 18, 2012, 6:07 p.m.
> When, the property test is embedded within a larger condition, a little
> restructuring is required to pull out the secondary conditions.  For
> example,
> 
>   if (symtab_variable_p (node)
>       && varpool (node)->finalized)
>     varpool_analyze_node (varpool (node));
> 
> becomes
> 
>   if (varpool_node *vnode = node->try_variable ())
>     if (vnode->finalized)
>       varpool_analyze_node (vnode);

Please avoid cascading if's like this, use the existing && idiom instead.
Lawrence Crowl - Sept. 18, 2012, 6:36 p.m.
On 9/18/12, Eric Botcazou <ebotcazou@adacore.com> wrote:
>> When, the property test is embedded within a larger condition, a little
>> restructuring is required to pull out the secondary conditions.  For
>> example,
>>
>>   if (symtab_variable_p (node)
>>       && varpool (node)->finalized)
>>     varpool_analyze_node (varpool (node));
>>
>> becomes
>>
>>   if (varpool_node *vnode = node->try_variable ())
>>     if (vnode->finalized)
>>       varpool_analyze_node (vnode);
>
> Please avoid cascading if's like this, use the existing && idiom instead.

The language syntax would bind the conditional into the intializer, as in

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

which does not type-match.

So, if you want the type saftey and performance, the cascade is really
unavoidable.
Richard Guenther - Sept. 18, 2012, 7:56 p.m.
On Tue, Sep 18, 2012 at 8:01 PM, Lawrence Crowl <crowl@googlers.com> wrote:
> Add functions symtab_node_def::try_function and symtab_node_def::try_variable.
> These function return a pointer to the more specific type (e.g. cgraph_node*)
> if and only if the general type (symtab_node aka symtab_node_def*) is an
> instance of the specific type.  These functions are essentially checked down
> casts.
>
> 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 = node->try_function ())
>     {
>       ....
>     }
>
> 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, a little
> restructuring is required to pull out the secondary conditions.  For example,
>
>   if (symtab_variable_p (node)
>       && varpool (node)->finalized)
>     varpool_analyze_node (varpool (node));
>
> becomes
>
>   if (varpool_node *vnode = node->try_variable ())
>     if (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 member functions symtab_node_def::is_function and
> symtab_node_def::is_variable.  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_tree.
>
>
> The new code bootstraps .616% faster with a 99% confidence of being faster.
>
>
> Tested on x86_64.
>
>
> Okay for trunk?
>
>
> Index: gcc/ChangeLog
>
> 2012-09-18  Lawrence Crowl  <crowl@google.com
>
>         * cgraph.h (varpool_node): Rename to varpool_node_for_tree.

Sure it should be varpool_node_for_decl, if any.  Or varpool_node_from_decl
(grep for what is more common)

>         Adjust callers to match.
>         (symtab_node_def::try_function): New.
>         Change most calls to symtab_function_p with calls to
>         symtab_node_def::try_function.
>         (symtab_node_def::try_variable): New.
>         Change most calls to symtab_variable_p with calls to
>         symtab_node_def::try_variable.
>         (symtab_function_p): Rename to symtab_node_def::is_function.
>         Adjust remaining callers to match.
>         (symtab_variable_p): Rename to symtab_node_def::is_variable.
>         Adjust remaining callers to match.
>         * cgraph.c (cgraph_node_for_asm): Remove redundant call to
>         symtab_node_for_asm.
>         * graphunit.c (symbol_finalized_and_needed): New.
>         (symbol_finalized): New.
>         (cgraph_analyze_functions): Split complicated conditionals out into
>         above new functions.
>
>
> Index: gcc/lto-symtab.c
> ===================================================================
> --- gcc/lto-symtab.c    (revision 191403)
> +++ gcc/lto-symtab.c    (working copy)
> @@ -743,7 +743,7 @@ lto_symtab_merge_cgraph_nodes_1 (void **
>         {
>           if (!prevailing->vnode)
>             {
> -             prevailing->vnode = varpool_node (prevailing->decl);
> +             prevailing->vnode = varpool_node_for_tree (prevailing->decl);
>               prevailing->vnode->alias = true;
>             }
>           lto_varpool_replace_node (e->vnode, prevailing->vnode);
> Index: gcc/cgraphbuild.c
> ===================================================================
> --- gcc/cgraphbuild.c   (revision 191403)
> +++ 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_tree (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_tree (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_tree (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_tree (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_tree (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_tree (decl);
>    struct record_reference_ctx ctx = {false, NULL};
>
>    ctx.varpool_node = node;
> Index: gcc/cgraph.c
> ===================================================================
> --- gcc/cgraph.c        (revision 191403)
> +++ gcc/cgraph.c        (working copy)
> @@ -506,9 +506,10 @@ 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 (; node; node = node->symbol.next_sharing_asm_name)
> +    if (cgraph_node *cn = node->try_function ())
> +      if (!cn->global.inlined_to)
> +       return cn;
>    return NULL;
>  }
>
> Index: gcc/cgraph.h
> ===================================================================
> --- gcc/cgraph.h        (revision 191403)
> +++ gcc/cgraph.h        (working copy)
> @@ -448,13 +448,46 @@ struct GTY(()) asm_node {
>  /* Symbol table entry.  */
>  union GTY((desc ("%h.symbol.type"), chain_next ("%h.symbol.next"),
>            chain_prev ("%h.symbol.previous"))) symtab_node_def {
> +  /* Dynamic type testers. */
> +  bool GTY((skip)) is_function ();
> +  bool GTY((skip)) is_variable ();
> +  /* Conditional accessors return null if not the requested type.  */
> +  cgraph_node * GTY((skip)) try_function ();
> +  varpool_node * GTY((skip)) try_variable ();
> +
>    struct symtab_node_base GTY ((tag ("SYMTAB_SYMBOL"))) symbol;
> -  /* Use cgraph (symbol) accessor to get cgraph_node.  */
> +  /* To access the following fields,
> +     use the conditional accessors try_function and try_variable above
> +     or the asserting accessor functions cgraph and varpool.  */
>    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;
>  };
>
> +inline bool
> +symtab_node_def::is_function ()
> +{
> +  return symbol.type == SYMTAB_FUNCTION;
> +}
> +
> +inline bool
> +symtab_node_def::is_variable ()
> +{
> +  return symbol.type == SYMTAB_VARIABLE;
> +}
> +
> +inline cgraph_node *
> +symtab_node_def::try_function ()
> +{
> +  return is_function () ? &x_function : NULL;
> +}
> +
> +inline varpool_node *
> +symtab_node_def::try_variable()
> +{
> +  return is_variable () ? &x_variable : NULL;
> +}
> +
> +
>  extern GTY(()) symtab_node symtab_nodes;
>  extern GTY(()) int cgraph_n_nodes;
>  extern GTY(()) int cgraph_max_uid;
> @@ -677,7 +710,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_tree (tree);
>  struct varpool_node *varpool_node_for_asm (tree asmname);
>  void varpool_mark_needed_node (struct varpool_node *);
>  void debug_varpool (void);
> @@ -705,19 +738,6 @@ bool varpool_for_node_and_aliases (struc
>                                    void *, bool);
>  void varpool_add_new_variable (tree);
>
> -/* 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 *
> @@ -791,8 +811,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 = node->try_variable ())
> +       return vnode;
>      }
>    return NULL;
>  }
> @@ -804,8 +824,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 = node1->try_variable ())
> +       return vnode1;
>      }
>    return NULL;
>  }
> @@ -822,9 +842,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);
> +      if (varpool_node *vnode = node->try_variable ())
> +       if (DECL_INITIAL (node->symbol.decl))
> +         return vnode;
>      }
>    return NULL;
>  }
> @@ -836,9 +856,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);
> +      if (varpool_node *vnode1 = node1->try_variable ())
> +       if (DECL_INITIAL (node1->symbol.decl))
> +         return vnode1;
>      }
>    return NULL;
>  }
> @@ -855,8 +875,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);
> +      if (varpool_node *vnode = node->try_variable ())
> +       if (vnode->analyzed)
> +         return vnode;
>      }
>    return NULL;
>  }
> @@ -868,8 +889,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);
> +      if (varpool_node *vnode1 = node1->try_variable ())
> +       if (vnode1->analyzed)
> +         return vnode1;
>      }
>    return NULL;
>  }
> @@ -885,8 +907,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);
> +      if (cgraph_node *cn = node->try_function ())
> +       if (cn->analyzed)
> +         return cn;
>      }
>    return NULL;
>  }
> @@ -898,8 +921,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);
> +      if (cgraph_node *cn1 = node1->try_function ())
> +       if (cn1->analyzed)
> +         return cn1;
>      }
>    return NULL;
>  }
> @@ -916,8 +940,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 = node->try_function ())
> +       return cn;
>      }
>    return NULL;
>  }
> @@ -929,8 +953,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 = node1->try_function ())
> +       return cn1;
>      }
>    return NULL;
>  }
> @@ -958,9 +982,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);
> +      if (cgraph_node *cn = node->try_function ())
> +       if (cgraph_function_with_gimple_body_p (cn))
> +         return cn;
>      }
>    return NULL;
>  }
> @@ -972,9 +996,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);
> +      if (cgraph_node *cn1 = node1->try_function ())
> +       if (cgraph_function_with_gimple_body_p (cn1))
> +         return cn1;
>      }
>    return NULL;
>  }
> @@ -1173,7 +1197,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 (ref->referred->is_function ())
>      return ipa_ref_node (ref);
>    return NULL;
>  }
> @@ -1187,7 +1211,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 (ref->referred->is_variable ())
>      return ipa_ref_varpool_node (ref);
>    return NULL;
>  }
> Index: gcc/tree-emutls.c
> ===================================================================
> --- gcc/tree-emutls.c   (revision 191403)
> +++ 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_tree (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_tree (to);
>    else if (!alias_of)
>      varpool_add_new_variable (to);
>    else
> Index: gcc/ipa-reference.c
> ===================================================================
> --- gcc/ipa-reference.c (revision 191403)
> +++ 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 (!ref->referred->is_variable ())
>         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,29 +992,31 @@ 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))
> -         && referenced_from_this_partition_p (&vnode->symbol.ref_list, encoder))
> +      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
> +      if (varpool_node *vnode = snode->try_variable ())
>         {
> -         tree decl = vnode->symbol.decl;
> -         bitmap_set_bit (ltrans_statics, DECL_UID (decl));
> -         splay_tree_insert (reference_vars_to_consider,
> -                            DECL_UID (decl), (splay_tree_value)decl);
> -         ltrans_statics_bitcount ++;
> +         if (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;
> +             bitmap_set_bit (ltrans_statics, DECL_UID (decl));
> +             splay_tree_insert (reference_vars_to_consider,
> +                                DECL_UID (decl), (splay_tree_value)decl);
> +             ltrans_statics_bitcount ++;
> +           }
>         }
>      }
>
>
>    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))
> -         count++;
> +      {
> +       symtab_node snode = lto_symtab_encoder_deref (encoder, i);
> +       if (cgraph_node *cnode = snode->try_function ())
> +         if (write_node_summary_p (cnode, encoder, ltrans_statics))
> +           count++;
> +      }
>
>    streamer_write_uhwi_stream (ob->main_stream, count);
>    if (count)
> @@ -1027,24 +1027,22 @@ 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))
> -         {
> -           ipa_reference_optimization_summary_t info;
> -           int node_ref;
> +       symtab_node snode = lto_symtab_encoder_deref (encoder, i);
> +       if (cgraph_node *cnode = snode->try_function ())
> +         if (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);
> -           streamer_write_uhwi_stream (ob->main_stream, node_ref);
> +             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,
> -                              ltrans_statics_bitcount);
> -           stream_out_bitmap (ob, info->statics_not_written, ltrans_statics,
> -                              ltrans_statics_bitcount);
> -         }
> +             stream_out_bitmap (ob, info->statics_not_read, ltrans_statics,
> +                                ltrans_statics_bitcount);
> +             stream_out_bitmap (ob, info->statics_not_written, ltrans_statics,
> +                                ltrans_statics_bitcount);
> +           }
>        }
>    BITMAP_FREE (ltrans_statics);
>    lto_destroy_simple_output_block (ob);
> Index: gcc/cgraphunit.c
> ===================================================================
> --- gcc/cgraphunit.c    (revision 191403)
> +++ gcc/cgraphunit.c    (working copy)
> @@ -388,8 +388,9 @@ 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)
> -    return true;
> +  if (cgraph_node *cn = node->try_function ())
> +    if (cn->callers)
> +      return true;
>    return false;
>  }
>
> @@ -818,7 +819,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_tree (decl);
>
>    gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl));
>
> @@ -845,6 +846,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 = node->try_function ())
> +    return cnode->local.finalized
> +          && cgraph_decide_is_function_needed (cnode, cnode->symbol.decl);
> +  if (varpool_node *vnode = node->try_variable ())
> +    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= node->try_function ())
> +    return cnode->local.finalized;
> +  if (varpool_node *vnode = node->try_variable ())
> +    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  */
>
> @@ -879,13 +909,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)
> @@ -912,49 +936,50 @@ cgraph_analyze_functions (void)
>           changed = true;
>           node = first;
>           first = (symtab_node)first->symbol.aux;
> -         if (symtab_function_p (node) && cgraph (node)->local.finalized)
> +         if (cgraph_node *cnode = node->try_function ())
>             {
> -             struct cgraph_edge *edge;
> -             struct cgraph_node *cnode;
> -             tree decl;
> -
> -             cnode = cgraph (node);
> -             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  */
> -             if (!DECL_STRUCT_FUNCTION (decl)
> -                 && (!cnode->alias || !cnode->thunk.alias)
> -                 && !cnode->thunk.thunk_p)
> +             if (cnode->local.finalized)
>                 {
> -                 cgraph_reset_node (cnode);
> -                 cnode->local.redefined_extern_inline = true;
> -                 continue;
> -               }
> +                 struct cgraph_edge *edge;
> +                 tree decl = cnode->symbol.decl;
>
> -             if (!cnode->analyzed)
> -               cgraph_analyze_function (cnode);
> +                 /* ??? 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)
> +                   {
> +                     cgraph_reset_node (cnode);
> +                     cnode->local.redefined_extern_inline = true;
> +                     continue;
> +                   }
>
> -             for (edge = cnode->callees; edge; edge = edge->next_callee)
> -               if (edge->callee->local.finalized)
> -                 enqueue_node ((symtab_node)edge->callee);
> +                 if (!cnode->analyzed)
> +                   cgraph_analyze_function (cnode);
>
> -             /* 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));
> -                 origin_node->abstract_and_needed = true;
> -               }
> +                 for (edge = cnode->callees; edge; edge = edge->next_callee)
> +                   if (edge->callee->local.finalized)
> +                      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_ABSTRACT_ORIGIN (decl))
> +                   {
> +                     struct cgraph_node *origin_node
> +                         = cgraph_get_node (DECL_ABSTRACT_ORIGIN (decl));
> +                     origin_node->abstract_and_needed = true;
> +                   }
> +               }
> +           }
> +         else
> +           {
> +             if (varpool_node *vnode = node->try_variable ())
> +               if (vnode->finalized)
> +                 varpool_analyze_node (vnode);
>             }
> -         else if (symtab_variable_p (node)
> -                  && varpool (node)->finalized)
> -           varpool_analyze_node (varpool (node));
>
>           if (node->symbol.same_comdat_group)
>             {
> @@ -965,9 +990,9 @@ 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 ();
>         }
>      }
> @@ -994,10 +1019,9 @@ cgraph_analyze_functions (void)
>           symtab_remove_node (node);
>           continue;
>         }
> -      if (symtab_function_p (node))
> +      if (cgraph_node *cnode = node->try_function ())
>         {
>           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)
> @@ -1079,7 +1103,7 @@ handle_alias_pairs (void)
>         }
>
>        if (TREE_CODE (p->decl) == FUNCTION_DECL
> -          && target_node && symtab_function_p (target_node))
> +          && target_node && target_node->is_function ())
>         {
>           struct cgraph_node *src_node = cgraph_get_node (p->decl);
>           if (src_node && src_node->local.finalized)
> @@ -1088,7 +1112,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 && target_node->is_variable ())
>         {
>           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 191403)
> +++ gcc/cp/decl2.c      (working copy)
> @@ -1773,7 +1773,7 @@ import_export_class (tree ctype)
>  static bool
>  var_finalized_p (tree var)
>  {
> -  return varpool_node (var)->finalized;
> +  return varpool_node_for_tree (var)->finalized;
>  }
>
>  /* DECL is a VAR_DECL or FUNCTION_DECL which, for whatever reason,
> @@ -1891,7 +1891,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_tree (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 191403)
> +++ 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 || referring_node->is_function ());
>    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 191403)
> +++ gcc/lto-cgraph.c    (working copy)
> @@ -665,7 +665,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 (ref->referred->is_function ())
>        add_node_to (encoder, ipa_ref_node (ref), false);
>      else
>        {
> @@ -719,9 +719,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 = node->try_variable ())
>         {
> -         struct varpool_node *vnode = varpool (node);
>           if (DECL_INITIAL (vnode->symbol.decl)
>               && !lto_symtab_encoder_encode_initializer_p (encoder,
>                                                            vnode)
> @@ -785,8 +784,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 = node->try_function ())
> +        lto_output_node (ob, cnode, encoder);
>        else
>          lto_output_varpool_node (ob, varpool (node), encoder);
>
> @@ -972,7 +971,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_tree (var_decl);
>    node->symbol.order = order;
>    if (order >= symtab_order)
>      symtab_order = order + 1;
> @@ -1133,14 +1132,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 || !node->is_function ());
>  #endif
>    FOR_EACH_VEC_ELT (symtab_node, nodes, i, node)
>      {
>        int ref;
> -      if (symtab_function_p (node))
> +      if (cgraph_node *cnode = node->try_function ())
>         {
> -         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)
> @@ -1149,9 +1148,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;
> @@ -1163,7 +1162,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 = node->is_function () ? (void *)1 : NULL;
>    return nodes;
>  }
>
> @@ -1437,7 +1436,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);
> @@ -1447,19 +1445,22 @@ 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);
> +      if (cgraph_node *cnode = node->try_function ())
> +       if (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)))
> -       {
> -         streamer_write_uhwi (ob, i);
> -         output_node_opt_summary (ob, cgraph (node), encoder);
> -       }
> +      symtab_node node = lto_symtab_encoder_deref (encoder, i);
> +      if (cgraph_node *cnode = node->try_function ())
> +       if (output_cgraph_opt_summary_p (cnode))
> +         {
> +           streamer_write_uhwi (ob, i);
> +           output_node_opt_summary (ob, cnode, encoder);
> +         }
>      }
>    produce_asm (ob, NULL);
>    destroy_output_block (ob);
> Index: gcc/lto-streamer-out.c
> ===================================================================
> --- gcc/lto-streamer-out.c      (revision 191403)
> +++ gcc/lto-streamer-out.c      (working copy)
> @@ -975,7 +975,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 ();
> @@ -991,27 +990,25 @@ 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)
> -         && !node->alias
> -         && !node->thunk.thunk_p)
> -       {
> +      if (cgraph_node *node = snode->try_function ())
> +       if (lto_symtab_encoder_encode_body_p (encoder, node)
> +           && !node->alias
> +           && !node->thunk.thunk_p)
> +         {
>  #ifdef ENABLE_CHECKING
> -         gcc_assert (!bitmap_bit_p (output, DECL_UID (node->symbol.decl)));
> -         bitmap_set_bit (output, DECL_UID (node->symbol.decl));
> +           gcc_assert (!bitmap_bit_p (output, DECL_UID (node->symbol.decl)));
> +           bitmap_set_bit (output, DECL_UID (node->symbol.decl));
>  #endif
> -         decl_state = lto_new_out_decl_state ();
> -         lto_push_out_decl_state (decl_state);
> -         if (gimple_has_body_p (node->symbol.decl))
> -           output_function (node);
> -         else
> -           copy_function (node);
> -         gcc_assert (lto_get_out_decl_state () == decl_state);
> -         lto_pop_out_decl_state ();
> -         lto_record_function_out_decl_state (node->symbol.decl, decl_state);
> -       }
> +           decl_state = lto_new_out_decl_state ();
> +           lto_push_out_decl_state (decl_state);
> +           if (gimple_has_body_p (node->symbol.decl))
> +             output_function (node);
> +           else
> +             copy_function (node);
> +           gcc_assert (lto_get_out_decl_state () == decl_state);
> +           lto_pop_out_decl_state ();
> +           lto_record_function_out_decl_state (node->symbol.decl, decl_state);
> +         }
>      }
>
>    /* Emit the callgraph after emitting function bodies.  This needs to
> @@ -1288,8 +1285,6 @@ produce_symtab (struct output_block *ob)
>    struct streamer_tree_cache_d *cache = ob->writer_cache;
>    char *section_name = lto_get_section_name (LTO_section_symtab, NULL, NULL);
>    struct pointer_set_t *seen;
> -  struct cgraph_node *node;
> -  struct varpool_node *vnode;
>    struct lto_output_stream stream;
>    lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
>    int i;
> @@ -1305,73 +1300,77 @@ produce_symtab (struct output_block *ob)
>       This is done so only to handle duplicated symbols in cgraph.  */
>    for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
>      {
> -      if (!symtab_function_p (lto_symtab_encoder_deref (encoder, i)))
> -       continue;
> -      node = cgraph (lto_symtab_encoder_deref (encoder, i));
> -      if (DECL_EXTERNAL (node->symbol.decl))
> -       continue;
> -      if (DECL_COMDAT (node->symbol.decl)
> -         && cgraph_comdat_can_be_unshared_p (node))
> -       continue;
> -      if ((node->alias && !node->thunk.alias) || node->global.inlined_to)
> -       continue;
> -      write_symbol (cache, &stream, node->symbol.decl, seen, false);
> +      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
> +      if (cgraph_node *cnode = snode->try_function ())
> +       {
> +         if (DECL_EXTERNAL (cnode->symbol.decl))
> +           continue;
> +         if (DECL_COMDAT (cnode->symbol.decl)
> +             && cgraph_comdat_can_be_unshared_p (cnode))
> +           continue;
> +         if ((cnode->alias && !cnode->thunk.alias) || cnode->global.inlined_to)
> +           continue;
> +         write_symbol (cache, &stream, cnode->symbol.decl, seen, false);
> +       }
>      }
>    for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
>      {
> -      if (!symtab_function_p (lto_symtab_encoder_deref (encoder, i)))
> -       continue;
> -      node = cgraph (lto_symtab_encoder_deref (encoder, i));
> -      if (!DECL_EXTERNAL (node->symbol.decl))
> -       continue;
> -      /* We keep around unused extern inlines in order to be able to inline
> -        them indirectly or via vtables.  Do not output them to symbol
> -        table: they end up being undefined and just consume space.  */
> -      if (!node->symbol.address_taken && !node->callers)
> -       continue;
> -      if (DECL_COMDAT (node->symbol.decl)
> -         && cgraph_comdat_can_be_unshared_p (node))
> -       continue;
> -      if ((node->alias && !node->thunk.alias) || node->global.inlined_to)
> -       continue;
> -      write_symbol (cache, &stream, node->symbol.decl, seen, false);
> +      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
> +      if (cgraph_node *cnode = snode->try_function ())
> +       {
> +         if (!DECL_EXTERNAL (cnode->symbol.decl))
> +           continue;
> +         /* We keep around unused extern inlines in order to be able to inline
> +            them indirectly or via vtables.  Do not output them to symbol
> +            table: they end up being undefined and just consume space.  */
> +         if (!cnode->symbol.address_taken && !cnode->callers)
> +           continue;
> +         if (DECL_COMDAT (cnode->symbol.decl)
> +             && cgraph_comdat_can_be_unshared_p (cnode))
> +           continue;
> +         if ((cnode->alias && !cnode->thunk.alias) || cnode->global.inlined_to)
> +           continue;
> +         write_symbol (cache, &stream, cnode->symbol.decl, seen, false);
> +       }
>      }
>
>    /* Write all variables.  */
>    for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
>      {
> -      if (!symtab_variable_p (lto_symtab_encoder_deref (encoder, i)))
> -       continue;
> -      vnode = varpool (lto_symtab_encoder_deref (encoder, i));
> -      if (DECL_EXTERNAL (vnode->symbol.decl))
> -       continue;
> -      /* COMDAT virtual tables can be unshared.  Do not declare them
> -        in the LTO symbol table to prevent linker from forcing them
> -        into the output. */
> -      if (DECL_COMDAT (vnode->symbol.decl)
> -         && !vnode->symbol.force_output
> -         && vnode->finalized
> -         && DECL_VIRTUAL_P (vnode->symbol.decl))
> -       continue;
> -      if (vnode->alias && !vnode->alias_of)
> -       continue;
> -      write_symbol (cache, &stream, vnode->symbol.decl, seen, false);
> +      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
> +      if (varpool_node *vnode = snode->try_variable ())
> +       {
> +         if (DECL_EXTERNAL (vnode->symbol.decl))
> +           continue;
> +         /* COMDAT virtual tables can be unshared.  Do not declare them
> +            in the LTO symbol table to prevent linker from forcing them
> +            into the output. */
> +         if (DECL_COMDAT (vnode->symbol.decl)
> +             && !vnode->symbol.force_output
> +             && vnode->finalized
> +             && DECL_VIRTUAL_P (vnode->symbol.decl))
> +           continue;
> +         if (vnode->alias && !vnode->alias_of)
> +           continue;
> +         write_symbol (cache, &stream, vnode->symbol.decl, seen, false);
> +       }
>      }
>    for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
>      {
> -      if (!symtab_variable_p (lto_symtab_encoder_deref (encoder, i)))
> -       continue;
> -      vnode = varpool (lto_symtab_encoder_deref (encoder, i));
> -      if (!DECL_EXTERNAL (vnode->symbol.decl))
> -       continue;
> -      if (DECL_COMDAT (vnode->symbol.decl)
> -         && !vnode->symbol.force_output
> -         && vnode->finalized
> -         && DECL_VIRTUAL_P (vnode->symbol.decl))
> -       continue;
> -      if (vnode->alias && !vnode->alias_of)
> -       continue;
> -      write_symbol (cache, &stream, vnode->symbol.decl, seen, false);
> +      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
> +      if (varpool_node *vnode = snode->try_variable ())
> +       {
> +         if (!DECL_EXTERNAL (vnode->symbol.decl))
> +           continue;
> +         if (DECL_COMDAT (vnode->symbol.decl)
> +             && !vnode->symbol.force_output
> +             && vnode->finalized
> +             && DECL_VIRTUAL_P (vnode->symbol.decl))
> +           continue;
> +         if (vnode->alias && !vnode->alias_of)
> +           continue;
> +         write_symbol (cache, &stream, vnode->symbol.decl, seen, false);
> +       }
>      }
>
>    lto_write_stream (&stream);
> Index: gcc/ada/gcc-interface/utils.c
> ===================================================================
> --- gcc/ada/gcc-interface/utils.c       (revision 191403)
> +++ gcc/ada/gcc-interface/utils.c       (working copy)
> @@ -5582,7 +5582,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_tree (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 191403)
> +++ 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 (ref->referred->is_function ())
>         {
>           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 = node->try_function ())
>         {
> -         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)
> @@ -331,19 +329,21 @@ 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)
> -         && DECL_EXTERNAL (node->symbol.decl)
> -         && !varpool (node)->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++)
> -           enqueue_node (ref->referred, &first, reachable);
> -        }
> +      /* When we see constructor of external variable, keep referred nodes
> +        in the boundary.  This will also hold initializers of the external
> +        vars NODE refers to.  */
> +      if (varpool_node *vnode = node->try_variable ())
> +       if (DECL_EXTERNAL (node->symbol.decl)
> +           && !vnode->alias
> +           && in_boundary_p)
> +         {
> +           struct ipa_ref *ref;
> +           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 +526,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 (ref->referring->is_function ())
>           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 191403)
> +++ gcc/ipa-inline-analysis.c   (working copy)
> @@ -3816,65 +3816,68 @@ 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);
> +      if (cgraph_node *cnode = snode->try_function ())
> +       if (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)
> -       {
> -         struct inline_summary *info = inline_summary (node);
> -         struct bitpack_d bp;
> -         struct cgraph_edge *edge;
> -         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);
> -         streamer_write_hwi (ob, info->self_time);
> -         bp = bitpack_create (ob->main_stream);
> -         bp_pack_value (&bp, info->inlinable, 1);
> -         streamer_write_bitpack (&bp);
> -         streamer_write_uhwi (ob, VEC_length (condition, info->conds));
> -         for (i = 0; VEC_iterate (condition, info->conds, i, c); i++)
> -           {
> -             streamer_write_uhwi (ob, c->operand_num);
> -             streamer_write_uhwi (ob, c->code);
> -             stream_write_tree (ob, c->val, true);
> -             bp = bitpack_create (ob->main_stream);
> -             bp_pack_value (&bp, c->agg_contents, 1);
> -             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, VEC_length (size_time_entry, info->entry));
> -         for (i = 0;
> -              VEC_iterate (size_time_entry, info->entry, i, e);
> -              i++)
> -           {
> -             streamer_write_uhwi (ob, e->size);
> -             streamer_write_uhwi (ob, e->time);
> -             write_predicate (ob, &e->predicate);
> -           }
> -         write_predicate (ob, info->loop_iterations);
> -         write_predicate (ob, info->loop_stride);
> -         for (edge = node->callees; edge; edge = edge->next_callee)
> -           write_inline_edge_summary (ob, edge);
> -         for (edge = node->indirect_calls; edge; edge = edge->next_callee)
> -           write_inline_edge_summary (ob, edge);
> +      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
> +      if (cgraph_node *cnode = snode->try_function ())
> +       if ((node = cnode)->analyzed)
> +         {
> +           struct inline_summary *info = inline_summary (node);
> +           struct bitpack_d bp;
> +           struct cgraph_edge *edge;
> +           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);
> +           streamer_write_hwi (ob, info->self_time);
> +           bp = bitpack_create (ob->main_stream);
> +           bp_pack_value (&bp, info->inlinable, 1);
> +           streamer_write_bitpack (&bp);
> +           streamer_write_uhwi (ob, VEC_length (condition, info->conds));
> +           for (i = 0; VEC_iterate (condition, info->conds, i, c); i++)
> +             {
> +               streamer_write_uhwi (ob, c->operand_num);
> +               streamer_write_uhwi (ob, c->code);
> +               stream_write_tree (ob, c->val, true);
> +               bp = bitpack_create (ob->main_stream);
> +               bp_pack_value (&bp, c->agg_contents, 1);
> +               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, VEC_length (size_time_entry, info->entry));
> +           for (i = 0;
> +                VEC_iterate (size_time_entry, info->entry, i, e);
> +                i++)
> +             {
> +               streamer_write_uhwi (ob, e->size);
> +               streamer_write_uhwi (ob, e->time);
> +               write_predicate (ob, &e->predicate);
> +             }
> +           write_predicate (ob, info->loop_iterations);
> +           write_predicate (ob, info->loop_stride);
> +           for (edge = node->callees; edge; edge = edge->next_callee)
> +             write_inline_edge_summary (ob, edge);
> +           for (edge = node->indirect_calls; edge; edge = edge->next_callee)
> +             write_inline_edge_summary (ob, edge);
>         }
>      }
>    streamer_write_char_stream (ob->main_stream, 0);
> Index: gcc/lto/lto.c
> ===================================================================
> --- gcc/lto/lto.c       (revision 191403)
> +++ gcc/lto/lto.c       (working copy)
> @@ -2619,12 +2619,16 @@ 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)))
> -                   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)");
> +                 if (cgraph_node *cnode = node->try_function ())
> +                   {
> +                     if (lto_symtab_encoder_encode_body_p (part->encoder, cnode))
> +                     fprintf (cgraph_dump_file, "(body included)");
> +                   }
> +                 else if (varpool_node *vnode = node->try_variable ())
> +                   {
> +                     if (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 191403)
> +++ 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)
> -    return SYMBOL_DUPLICATE;
> +  if (cgraph_node *cnode = node->try_function ())
> +    if (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 = node->try_variable ())
>      {
>        /* 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 (ref->referred->is_variable ()
>              && 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 = node->try_function ())
>      {
> -      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 = node->try_function ())
>      {
> -      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 = node->try_variable ())
> +    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 = node->try_function ())
> +        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 = snode->try_function ())
>             {
>               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 (ref->referred->is_variable ())
>               {
>                 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 (ref->referring->is_variable ())
>               {
>                 int index;
>
> Index: gcc/varasm.c
> ===================================================================
> --- gcc/varasm.c        (revision 191403)
> +++ 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_tree (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_tree (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 191403)
> +++ gcc/symtab.c        (working copy)
> @@ -239,8 +239,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 = node->try_function ())
> +       replacement_node = (symtab_node)cgraph_find_replacement_node (cnode);
>        if (!replacement_node)
>         htab_clear_slot (symtab_hash, slot);
>        else
> @@ -281,10 +281,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 = node->try_function ())
> +    cgraph_remove_node (cnode);
> +  else if (varpool_node *vnode = node->try_variable ())
> +    varpool_remove_node (vnode);
>  }
>
>  /* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME.
> @@ -514,10 +514,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 = node->try_function ())
> +    dump_cgraph_node (f, cnode);
> +  else if (varpool_node *vnode = node->try_variable ())
> +    dump_varpool_node (f, vnode);
>  }
>
>  /* Dump symbol table.  */
> @@ -555,7 +555,7 @@ verify_symtab_base (symtab_node node)
>    bool error_found = false;
>    symtab_node hashed_node;
>
> -  if (symtab_function_p (node))
> +  if (node->is_function ())
>      {
>        if (TREE_CODE (node->symbol.decl) != FUNCTION_DECL)
>         {
> @@ -563,7 +563,7 @@ verify_symtab_base (symtab_node node)
>            error_found = true;
>         }
>      }
> -  else if (symtab_variable_p (node))
> +  else if (node->is_variable ())
>      {
>        if (TREE_CODE (node->symbol.decl) != VAR_DECL)
>         {
> @@ -651,8 +651,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 = node->try_function ())
> +    verify_cgraph_node (cnode);
>    else
>      if (verify_symtab_base (node))
>        {
> Index: gcc/passes.c
> ===================================================================
> --- gcc/passes.c        (revision 191403)
> +++ 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_tree (decl);
>  }
>
>  /* Called after finishing a record, union or enumeral type.  */
> Index: gcc/varpool.c
> ===================================================================
> --- gcc/varpool.c       (revision 191403)
> +++ 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_tree (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 = node->try_variable ())
> +      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_tree (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_tree (node->alias_of);
>        struct varpool_node *n;
>
>        for (n = tgt; n && n->alias;
> @@ -374,16 +374,15 @@ 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);
> +           if (varpool_node *vnext = next->try_variable ())
> +             if (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);
> +       if (varpool_node *vnode = ref->referred->try_variable ())
> +         if ((!DECL_EXTERNAL (ref->referred->symbol.decl) || vnode->alias)
> +             && vnode->analyzed)
> +           enqueue_node (vnode, &first);
>      }
>    if (cgraph_dump_file)
>      fprintf (cgraph_dump_file, "\nRemoving variables:");
> @@ -457,7 +456,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_tree (new_decl);
>    varpool_finalize_decl (new_decl);
>
>    return new_node->symbol.decl;
> @@ -473,7 +472,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_tree (alias);
>    alias_node->alias = 1;
>    alias_node->finalized = 1;
>    alias_node->alias_of = decl;
> Index: gcc/lto-streamer.h
> ===================================================================
> --- gcc/lto-streamer.h  (revision 191403)
> +++ gcc/lto-streamer.h  (working copy)
> @@ -1121,7 +1121,7 @@ lsei_next_function_in_partition (lto_sym
>  {
>    lsei_next (lsei);
>    while (!lsei_end_p (*lsei)
> -        && (!symtab_function_p (lsei_node (*lsei))
> +        && (!lsei_node (*lsei)->is_function ()
>              || !lto_symtab_encoder_in_partition_p (lsei->encoder, lsei_node
> (*lsei))))
>      lsei_next (lsei);
>  }
> @@ -1134,7 +1134,7 @@ lsei_start_function_in_partition (lto_sy
>
>    if (lsei_end_p (lsei))
>      return lsei;
> -  if (!symtab_function_p (lsei_node (lsei))
> +  if (!(lsei_node (lsei)->is_function ())
>        || !lto_symtab_encoder_in_partition_p (encoder, lsei_node (lsei)))
>      lsei_next_function_in_partition (&lsei);
>
> @@ -1147,7 +1147,7 @@ lsei_next_variable_in_partition (lto_sym
>  {
>    lsei_next (lsei);
>    while (!lsei_end_p (*lsei)
> -        && (!symtab_variable_p (lsei_node (*lsei))
> +        && (!lsei_node (*lsei)->is_variable ()
>              || !lto_symtab_encoder_in_partition_p (lsei->encoder, lsei_node
> (*lsei))))
>      lsei_next (lsei);
>  }
> @@ -1160,7 +1160,7 @@ lsei_start_variable_in_partition (lto_sy
>
>    if (lsei_end_p (lsei))
>      return lsei;
> -  if (!symtab_variable_p (lsei_node (lsei))
> +  if (!lsei_node (lsei)->is_variable ()
>        || !lto_symtab_encoder_in_partition_p (encoder, lsei_node (lsei)))
>      lsei_next_variable_in_partition (&lsei);
>
> --
> Lawrence Crowl
Lawrence Crowl - Sept. 18, 2012, 8:32 p.m.
On 9/18/12, Richard Guenther <richard.guenther@gmail.com> wrote:
> On Sep 18, 2012 Lawrence Crowl <crowl@googlers.com> wrote:
> > * cgraph.h (varpool_node): Rename to varpool_node_for_tree.
>
> Sure it should be varpool_node_for_decl, if any.
> Or varpool_node_from_decl (grep for what is more common)

Grep says _for_decl wins over _from_decl by 113 to 74.
I will make that change unless I hear an objection soon.
Eric Botcazou - Sept. 19, 2012, 7:29 a.m.
> 
> The language syntax would bind the conditional into the intializer, as in
> 
>   if (varpool_node *vnode = (node->try_variable ()
>                              && vnode->finalized))
>     varpool_analyze_node (vnode);
> 
> which does not type-match.
> 
> So, if you want the type saftey and performance, the cascade is really
> unavoidable.

Just write:

  varpool_node *vnode;

  if ((vnode = node->try_variable ()) && vnode->finalized)
    varpool_analyze_node (vnode);

This has been the standard style for the past 2 decades and trading it for 
cascading if's is really a bad idea.
Richard Guenther - Sept. 19, 2012, 9:17 a.m.
On Wed, Sep 19, 2012 at 9:29 AM, Eric Botcazou <ebotcazou@adacore.com> wrote:
>>
>> The language syntax would bind the conditional into the intializer, as in
>>
>>   if (varpool_node *vnode = (node->try_variable ()
>>                              && vnode->finalized))
>>     varpool_analyze_node (vnode);
>>
>> which does not type-match.
>>
>> So, if you want the type saftey and performance, the cascade is really
>> unavoidable.
>
> Just write:
>
>   varpool_node *vnode;
>
>   if ((vnode = node->try_variable ()) && vnode->finalized)
>     varpool_analyze_node (vnode);
>
> This has been the standard style for the past 2 decades and trading it for
> cascading if's is really a bad idea.

Indeed.  Btw, can we not provide a specialization for dynamic_cast <>?
This ->try_... looks awkward to me compared to the more familiar

  vnode = dynamic_cast <varpool_node> (node)

but yeah - dynamic_cast is not a template ... (but maybe there is some
standard library piece that mimics it?).

Richard.

> --
> Eric Botcazou
Gabriel Dos Reis - Sept. 19, 2012, 12:18 p.m.
On Wed, Sep 19, 2012 at 4:17 AM, Richard Guenther
<richard.guenther@gmail.com> wrote:
> On Wed, Sep 19, 2012 at 9:29 AM, Eric Botcazou <ebotcazou@adacore.com> wrote:
>>>
>>> The language syntax would bind the conditional into the intializer, as in
>>>
>>>   if (varpool_node *vnode = (node->try_variable ()
>>>                              && vnode->finalized))
>>>     varpool_analyze_node (vnode);
>>>
>>> which does not type-match.
>>>
>>> So, if you want the type saftey and performance, the cascade is really
>>> unavoidable.
>>
>> Just write:
>>
>>   varpool_node *vnode;
>>
>>   if ((vnode = node->try_variable ()) && vnode->finalized)
>>     varpool_analyze_node (vnode);
>>
>> This has been the standard style for the past 2 decades and trading it for
>> cascading if's is really a bad idea.
>
> Indeed.  Btw, can we not provide a specialization for dynamic_cast <>?

No, it is a language primitive.

but we can define out own operation with similar syntax that allows
for specialization, whose generic implementation uses dynamic_cast.

   template<typename T, typename U>
   T* is(U* u) {
       return dynamic_cast<T*>(u);
    }

> This ->try_... looks awkward to me compared to the more familiar
>
>   vnode = dynamic_cast <varpool_node> (node)
>
> but yeah - dynamic_cast is not a template ... (but maybe there is some
> standard library piece that mimics it?).



>
> Richard.
>
>> --
>> Eric Botcazou
Lawrence Crowl - Sept. 19, 2012, 6:27 p.m.
On 9/19/12, Eric Botcazou <ebotcazou@adacore.com> wrote:
> > The language syntax would bind the conditional into the
> > intializer, as in
> >
> >   if (varpool_node *vnode = (node->try_variable ()
> >                              && vnode->finalized))
> >     varpool_analyze_node (vnode);
> >
> > which does not type-match.
> >
> > So, if you want the type saftey and performance, the cascade
> > is really unavoidable.
>
> Just write:
>
>   varpool_node *vnode;
>
>   if ((vnode = node->try_variable ()) && vnode->finalized)
>     varpool_analyze_node (vnode);
>
> This has been the standard style for the past 2 decades and
> trading it for cascading if's is really a bad idea.

Assignments in if statements are known to cause confusion.

The point of the change is to limit the scope of the variable
to the if statement, which prevents its unintended use later.
It acts like a type switch.

Why do you think cascading ifs is a bad idea?
Lawrence Crowl - Sept. 19, 2012, 6:39 p.m.
On 9/19/12, Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:
> On Sep 19, 2012 Richard Guenther <richard.guenther@gmail.com> wrote:
> > Indeed.  Btw, can we not provide a specialization for
> > dynamic_cast <>?  This ->try_... looks awkward to me compared
> > to the more familiar
> >
> > vnode = dynamic_cast <varpool_node> (node)
> >
> > but yeah - dynamic_cast is not a template ... (but maybe there
> > is some standard library piece that mimics it?).
>
> No, it is a language primitive.
>
> but we can define out own operation with similar syntax that allows
> for specialization, whose generic implementation uses dynamic_cast.
>
>   template<typename T, typename U>
>   T* is(U* u) {
>       return dynamic_cast<T*>(u);
>   }

At this point, dynamic_cast is not available because we do not
yet have polymorphic types.  There has been some resistance to
that notion.

Absent dynamic cast, we need to specialize for various type
combinations.  Function template specialization would be handy,
but C++ does not directly support that.  We could work around
that.  However, in the end, the fact that try_whatever is a member
function means that we can use a notation that depends on context
and so can be shorter.  That is, we can write 'function' instead of
'cgraph_node *'.
Gabriel Dos Reis - Sept. 19, 2012, 9:14 p.m.
On Wed, Sep 19, 2012 at 1:39 PM, Lawrence Crowl <crowl@googlers.com> wrote:
> On 9/19/12, Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:
>> On Sep 19, 2012 Richard Guenther <richard.guenther@gmail.com> wrote:
>> > Indeed.  Btw, can we not provide a specialization for
>> > dynamic_cast <>?  This ->try_... looks awkward to me compared
>> > to the more familiar
>> >
>> > vnode = dynamic_cast <varpool_node> (node)
>> >
>> > but yeah - dynamic_cast is not a template ... (but maybe there
>> > is some standard library piece that mimics it?).
>>
>> No, it is a language primitive.
>>
>> but we can define out own operation with similar syntax that allows
>> for specialization, whose generic implementation uses dynamic_cast.
>>
>>   template<typename T, typename U>
>>   T* is(U* u) {
>>       return dynamic_cast<T*>(u);
>>   }
>
> At this point, dynamic_cast is not available because we do not
> yet have polymorphic types.  There has been some resistance to
> that notion.

Hmm, when did we rule that out?

We currently implement dynamic_cast using the poor man's simulation
based on tree_code checking.  We can just as well give such
simulation the is<> notation.

> Absent dynamic cast, we need to specialize for various type
> combinations.  Function template specialization would be handy,
> but C++ does not directly support that.  We could work around
> that.

We can always use the standard workaround: call a static member
function of a class template that can be specialized at will.

> However, in the end, the fact that try_whatever is a member
> function means that we can use a notation that depends on context
> and so can be shorter.  That is, we can write 'function' instead of
> 'cgraph_node *'.
>
> --
> Lawrence Crowl
Lawrence Crowl - Sept. 19, 2012, 9:46 p.m.
On 9/19/12, Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:
> On Wed, Sep 19, 2012 at 1:39 PM, Lawrence Crowl <crowl@googlers.com> wrote:
>> On 9/19/12, Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:
>>> On Sep 19, 2012 Richard Guenther <richard.guenther@gmail.com> wrote:
>>> > Indeed.  Btw, can we not provide a specialization for
>>> > dynamic_cast <>?  This ->try_... looks awkward to me compared
>>> > to the more familiar
>>> >
>>> > vnode = dynamic_cast <varpool_node> (node)
>>> >
>>> > but yeah - dynamic_cast is not a template ... (but maybe there
>>> > is some standard library piece that mimics it?).
>>>
>>> No, it is a language primitive.
>>>
>>> but we can define out own operation with similar syntax that allows
>>> for specialization, whose generic implementation uses dynamic_cast.
>>>
>>>   template<typename T, typename U>
>>>   T* is(U* u) {
>>>       return dynamic_cast<T*>(u);
>>>   }
>>
>> At this point, dynamic_cast is not available because we do not
>> yet have polymorphic types.  There has been some resistance to
>> that notion.
>
> Hmm, when did we rule that out?

We have not ruled it out, but folks are, rightly, concerned about any
size increase in critical data structures.  We are also currently
lacking a gengtype that will handle inheritance.  So, for now at
least, we need a scheme that will work across both inheritance and
our current tag/union approach.

> We currently implement dynamic_cast using the poor man's simulation
> based on tree_code checking.  We can just as well give such
> simulation the is<> notation.
>
>> Absent dynamic cast, we need to specialize for various type
>> combinations.  Function template specialization would be handy,
>> but C++ does not directly support that.  We could work around
>> that.
>
> We can always use the standard workaround: call a static member
> function of a class template that can be specialized at will.
>
>> However, in the end, the fact that try_whatever is a member
>> function means that we can use a notation that depends on context
>> and so can be shorter.  That is, we can write 'function' instead of
>> 'cgraph_node *'.
Michael Matz - Sept. 20, 2012, 1:08 p.m.
Hi,

On Wed, 19 Sep 2012, Richard Guenther wrote:

> > Just write:
> >
> >   varpool_node *vnode;
> >
> >   if ((vnode = node->try_variable ()) && vnode->finalized)
> >     varpool_analyze_node (vnode);
> >
> > This has been the standard style for the past 2 decades and trading it for
> > cascading if's is really a bad idea.
> 
> Indeed.  Btw, can we not provide a specialization for dynamic_cast <>?
> This ->try_... looks awkward to me compared to the more familiar
> 
>   vnode = dynamic_cast <varpool_node> (node)

Gah.  The less '<>' characters in source code the better.  I'm not 
thrilled, but prefer the ->try_ thingy.  And yes, cascading if's for this 
idiom is bad.


Ciao,
Michael.
Michael Matz - Sept. 20, 2012, 1:10 p.m.
Hi,

On Wed, 19 Sep 2012, Lawrence Crowl wrote:

> On 9/19/12, Eric Botcazou <ebotcazou@adacore.com> wrote:
> > > The language syntax would bind the conditional into the
> > > intializer, as in
> > >
> > >   if (varpool_node *vnode = (node->try_variable ()
> > >                              && vnode->finalized))
> > >     varpool_analyze_node (vnode);
> > >
> > > which does not type-match.
> > >
> > > So, if you want the type saftey and performance, the cascade
> > > is really unavoidable.
> >
> > Just write:
> >
> >   varpool_node *vnode;
> >
> >   if ((vnode = node->try_variable ()) && vnode->finalized)
> >     varpool_analyze_node (vnode);
> >
> > This has been the standard style for the past 2 decades and
> > trading it for cascading if's is really a bad idea.
> 
> Assignments in if statements are known to cause confusion.

So?  Make it:

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

> The point of the change is to limit the scope of the variable
> to the if statement, which prevents its unintended use later.

I'm not worried about this.

> Why do you think cascading ifs is a bad idea?

Precedent.  Confusion in case of dangling else (requiring more {}, and 
hence even more indentation).  Ugly.


Ciao,
Michael.
Lawrence Crowl - Sept. 20, 2012, 6:53 p.m.
On 9/20/12, Michael Matz <matz@suse.de> wrote:
> On Wed, 19 Sep 2012, Lawrence Crowl wrote:
> > On 9/19/12, Eric Botcazou <ebotcazou@adacore.com> wrote:
> > > > The language syntax would bind the conditional into the
> > > > intializer, as in
> > > >
> > > >   if (varpool_node *vnode = (node->try_variable ()
> > > >                              && vnode->finalized))
> > > >     varpool_analyze_node (vnode);
> > > >
> > > > which does not type-match.
> > > >
> > > > So, if you want the type saftey and performance, the cascade
> > > > is really unavoidable.
> > >
> > > Just write:
> > >
> > >   varpool_node *vnode;
> > >
> > >   if ((vnode = node->try_variable ()) && vnode->finalized)
> > >     varpool_analyze_node (vnode);
> > >
> > > This has been the standard style for the past 2 decades and
> > > trading it for cascading if's is really a bad idea.
> >
> > Assignments in if statements are known to cause confusion.
>
> So?  Make it:
>
>   varpool_node *vnode = node->try_variable ();
>   if (vnode && vnode->finalized)
>     varpool_analyze_node (vnode);
>
> > The point of the change is to limit the scope of the variable
> > to the if statement, which prevents its unintended use later.
>
> I'm not worried about this.

It is helpful to have the language and the usage in concurrence.

Okay, so unless someone objects, I'll move the variable out when
it introduces a cacade.

> > Why do you think cascading ifs is a bad idea?
>
> Precedent.  Confusion in case of dangling else (requiring more {},
> and hence even more indentation).  Ugly.

I generally take ugly as an indication that the function needs
refactoring.
Gabriel Dos Reis - Sept. 20, 2012, 9:50 p.m.
On Thu, Sep 20, 2012 at 1:53 PM, Lawrence Crowl <crowl@googlers.com> wrote:

>> > Why do you think cascading ifs is a bad idea?
>>
>> Precedent.  Confusion in case of dangling else (requiring more {},
>> and hence even more indentation).  Ugly.
>
> I generally take ugly as an indication that the function needs
> refactoring.

Hear!  Hear! Hear!

Sadly, many functions in GCC (at least in cp/) are in that category :-(

-- Gaby
Lawrence Crowl - Sept. 20, 2012, 10 p.m.
On 9/20/12, Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:
> On Sep 20, 2012 Lawrence Crowl <crowl@googlers.com> wrote:
> > > > Why do you think cascading ifs is a bad idea?
> > >
> > > Precedent.  Confusion in case of dangling else (requiring
> > > more {}, and hence even more indentation).  Ugly.
> >
> > I generally take ugly as an indication that the function needs
> > refactoring.
>
> Hear!  Hear! Hear!
>
> Sadly, many functions in GCC (at least in cp/) are in that
> category :-(

It is not just GCC.  Most large codebases I've seen have had lots of
large functions.  It takes persistent effort to beat back entropy.

I once chatted with a guy who worked on a project with a strict
requirement that every function fit on one screen, and that was
when screens were 24 lines.  He said their bug rate was really low.
And the one function they made an exception for turned out the have
the worst bug in it.
Xinliang David Li - Oct. 11, 2012, 5:16 a.m.
In a different thread, I proposed the following alternative to 'try_xxx':

template<typename T> T* symbol::cast_to(symbol* p) {
   if (p->is<T>())
      return static_cast<T*>(p);
   return 0;
 }

cast:

template<typename T> T& symbol:as(symbol* p) {
   assert(p->is<T>())
   return static_cast<T&>(*p);

 }

David

On Wed, Sep 19, 2012 at 2:17 AM, Richard Guenther
<richard.guenther@gmail.com> wrote:
> On Wed, Sep 19, 2012 at 9:29 AM, Eric Botcazou <ebotcazou@adacore.com> wrote:
>>>
>>> The language syntax would bind the conditional into the intializer, as in
>>>
>>>   if (varpool_node *vnode = (node->try_variable ()
>>>                              && vnode->finalized))
>>>     varpool_analyze_node (vnode);
>>>
>>> which does not type-match.
>>>
>>> So, if you want the type saftey and performance, the cascade is really
>>> unavoidable.
>>
>> Just write:
>>
>>   varpool_node *vnode;
>>
>>   if ((vnode = node->try_variable ()) && vnode->finalized)
>>     varpool_analyze_node (vnode);
>>
>> This has been the standard style for the past 2 decades and trading it for
>> cascading if's is really a bad idea.
>
> Indeed.  Btw, can we not provide a specialization for dynamic_cast <>?
> This ->try_... looks awkward to me compared to the more familiar
>
>   vnode = dynamic_cast <varpool_node> (node)
>
> but yeah - dynamic_cast is not a template ... (but maybe there is some
> standard library piece that mimics it?).
>
> Richard.
>
>> --
>> Eric Botcazou
Xinliang David Li - Oct. 11, 2012, 5:22 a.m.
On Wed, Sep 19, 2012 at 11:39 AM, Lawrence Crowl <crowl@googlers.com> wrote:
> On 9/19/12, Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:
>> On Sep 19, 2012 Richard Guenther <richard.guenther@gmail.com> wrote:
>> > Indeed.  Btw, can we not provide a specialization for
>> > dynamic_cast <>?  This ->try_... looks awkward to me compared
>> > to the more familiar
>> >
>> > vnode = dynamic_cast <varpool_node> (node)
>> >
>> > but yeah - dynamic_cast is not a template ... (but maybe there
>> > is some standard library piece that mimics it?).
>>
>> No, it is a language primitive.
>>
>> but we can define out own operation with similar syntax that allows
>> for specialization, whose generic implementation uses dynamic_cast.
>>
>>   template<typename T, typename U>
>>   T* is(U* u) {
>>       return dynamic_cast<T*>(u);
>>   }
>
> At this point, dynamic_cast is not available because we do not
> yet have polymorphic types.  There has been some resistance to
> that notion.
>
> Absent dynamic cast, we need to specialize for various type
> combinations.

The generic implementation can simply assert.

template<typename T> bool symbol::is()
{
  assert (0);
  return true;
}

template <> bool symbol::is<function>()
{
   if (type_ == FUNCTION)
     return true;
  return false;
}

template <> bool symbol::is<variable>()
{
   if (type_ == FUNCTION)
     return false;
  return true;
}

David

>  Function template specialization would be handy,
> but C++ does not directly support that.  We could work around
> that.  However, in the end, the fact that try_whatever is a member
> function means that we can use a notation that depends on context
> and so can be shorter.  That is, we can write 'function' instead of
> 'cgraph_node *'.
>
> --
> Lawrence Crowl
Lawrence Crowl - Oct. 11, 2012, 8:23 p.m.
On 10/10/12, Xinliang David Li <davidxl@google.com> wrote:
> In a different thread, I proposed the following alternative to 'try_xxx':
>
> template<typename T> T* symbol::cast_to(symbol* p) {
>    if (p->is<T>())
>       return static_cast<T*>(p);
>    return 0;
>  }
>
> cast:
>
> template<typename T> T& symbol:as(symbol* p) {
>    assert(p->is<T>())
>    return static_cast<T&>(*p);
>
>  }

My concern here was never the technical feasibility, nor the
desirability of having the facility for generic code, but the amount
of the amount of typing in non-generic contexts.  That is

  if (cgraph_node *q = p->try_function ())

versus

  if (cgraph_node *q = p->cast_to <cgraph_node *> ())

I thought the latter would generate objections.  Does anyone object
to the extra typing?

If not, I can make that change.
Xinliang David Li - Oct. 11, 2012, 8:39 p.m.
On Thu, Oct 11, 2012 at 1:23 PM, Lawrence Crowl <crowl@googlers.com> wrote:
> On 10/10/12, Xinliang David Li <davidxl@google.com> wrote:
>> In a different thread, I proposed the following alternative to 'try_xxx':
>>
>> template<typename T> T* symbol::cast_to(symbol* p) {
>>    if (p->is<T>())
>>       return static_cast<T*>(p);
>>    return 0;
>>  }
>>
>> cast:
>>
>> template<typename T> T& symbol:as(symbol* p) {
>>    assert(p->is<T>())
>>    return static_cast<T&>(*p);
>>
>>  }
>
> My concern here was never the technical feasibility, nor the
> desirability of having the facility for generic code, but the amount
> of the amount of typing in non-generic contexts.  That is
>
>   if (cgraph_node *q = p->try_function ())
>
> versus
>
>   if (cgraph_node *q = p->cast_to <cgraph_node *> ())
>
> I thought the latter would generate objections.  Does anyone object
> to the extra typing?
>
> If not, I can make that change.

Think about a more complex class hierarchy and interface consistency.
I believe you don't want this:

tree::try_decl () { .. }
tree::try_ssa_name () { ..}
tree::try_type() {...}
tree::try_int_const () {..}
tree::try_exp () { ...}
 ..

Rather one (or two with the const_cast version).

template <T> T *tree::cast_to ()
{
   if (kind_ == kind_traits<T>::value)
    return static_cast<T*> (this);

 return 0;
}


thanks,

David


>
> --
> Lawrence Crowl
Richard Guenther - Oct. 12, 2012, 8:22 a.m.
On Thu, Oct 11, 2012 at 10:39 PM, Xinliang David Li <davidxl@google.com> wrote:
> On Thu, Oct 11, 2012 at 1:23 PM, Lawrence Crowl <crowl@googlers.com> wrote:
>> On 10/10/12, Xinliang David Li <davidxl@google.com> wrote:
>>> In a different thread, I proposed the following alternative to 'try_xxx':
>>>
>>> template<typename T> T* symbol::cast_to(symbol* p) {
>>>    if (p->is<T>())
>>>       return static_cast<T*>(p);
>>>    return 0;
>>>  }
>>>
>>> cast:
>>>
>>> template<typename T> T& symbol:as(symbol* p) {
>>>    assert(p->is<T>())
>>>    return static_cast<T&>(*p);
>>>
>>>  }
>>
>> My concern here was never the technical feasibility, nor the
>> desirability of having the facility for generic code, but the amount
>> of the amount of typing in non-generic contexts.  That is
>>
>>   if (cgraph_node *q = p->try_function ())
>>
>> versus
>>
>>   if (cgraph_node *q = p->cast_to <cgraph_node *> ())
>>
>> I thought the latter would generate objections.  Does anyone object
>> to the extra typing?
>>
>> If not, I can make that change.
>
> Think about a more complex class hierarchy and interface consistency.
> I believe you don't want this:
>
> tree::try_decl () { .. }
> tree::try_ssa_name () { ..}
> tree::try_type() {...}
> tree::try_int_const () {..}
> tree::try_exp () { ...}
>  ..
>
> Rather one (or two with the const_cast version).
>
> template <T> T *tree::cast_to ()
> {
>    if (kind_ == kind_traits<T>::value)
>     return static_cast<T*> (this);
>
>  return 0;
> }

I also think that instead of

>>   if (cgraph_node *q = p->cast_to <cgraph_node *> ())

we want

  if ((q = cast_to <cgraph_node *> (p))

I see absolutely no good reason to make cast_to a member, given
that the language has static_cast, const_cast and stuff.  cast_to
would simply be our equivalent to dynamic_cast within our OO model.

Then I'd call it *_cast instead of cast_*, so, why not gcc_cast < >?
Or dyn_cast <> ().  That way

  if ((q = dyn_cast <function *> (p))

would be how to use it.  Small enough, compared to

  if ((q = p->try_function ()))

and a lot more familiar to folks knowing C++ (and probably doesn't make
a difference to others).

Thus, please re-use or follow existing concepts.

As for the example with tree we'd then have

  if ((q = dyn_cast <INTEGER_CST> (p)))

if we can overload on the template parameter kind (can we? typename vs. enum?)
or use tree_cast <> (no I don't want dyn_cast <tree_common> all around the
code).

Thanks,
Richard.

>
> thanks,
>
> David
>
>
>>
>> --
>> Lawrence Crowl
Xinliang David Li - Oct. 12, 2012, 7:21 p.m.
On Fri, Oct 12, 2012 at 1:22 AM, Richard Biener
<richard.guenther@gmail.com> wrote:
> On Thu, Oct 11, 2012 at 10:39 PM, Xinliang David Li <davidxl@google.com> wrote:
>> On Thu, Oct 11, 2012 at 1:23 PM, Lawrence Crowl <crowl@googlers.com> wrote:
>>> On 10/10/12, Xinliang David Li <davidxl@google.com> wrote:
>>>> In a different thread, I proposed the following alternative to 'try_xxx':
>>>>
>>>> template<typename T> T* symbol::cast_to(symbol* p) {
>>>>    if (p->is<T>())
>>>>       return static_cast<T*>(p);
>>>>    return 0;
>>>>  }
>>>>
>>>> cast:
>>>>
>>>> template<typename T> T& symbol:as(symbol* p) {
>>>>    assert(p->is<T>())
>>>>    return static_cast<T&>(*p);
>>>>
>>>>  }
>>>
>>> My concern here was never the technical feasibility, nor the
>>> desirability of having the facility for generic code, but the amount
>>> of the amount of typing in non-generic contexts.  That is
>>>
>>>   if (cgraph_node *q = p->try_function ())
>>>
>>> versus
>>>
>>>   if (cgraph_node *q = p->cast_to <cgraph_node *> ())
>>>
>>> I thought the latter would generate objections.  Does anyone object
>>> to the extra typing?
>>>
>>> If not, I can make that change.
>>
>> Think about a more complex class hierarchy and interface consistency.
>> I believe you don't want this:
>>
>> tree::try_decl () { .. }
>> tree::try_ssa_name () { ..}
>> tree::try_type() {...}
>> tree::try_int_const () {..}
>> tree::try_exp () { ...}
>>  ..
>>
>> Rather one (or two with the const_cast version).
>>
>> template <T> T *tree::cast_to ()
>> {
>>    if (kind_ == kind_traits<T>::value)
>>     return static_cast<T*> (this);
>>
>>  return 0;
>> }
>
> I also think that instead of
>
>>>   if (cgraph_node *q = p->cast_to <cgraph_node *> ())
>
> we want
>
>   if ((q = cast_to <cgraph_node *> (p))
>
> I see absolutely no good reason to make cast_to a member, given
> that the language has static_cast, const_cast and stuff.  cast_to
> would simply be our equivalent to dynamic_cast within our OO model.
>
> Then I'd call it *_cast instead of cast_*, so, why not gcc_cast < >?
> Or dyn_cast <> ().  That way
>
>   if ((q = dyn_cast <function *> (p))
>
> would be how to use it.  Small enough, compared to
>
>   if ((q = p->try_function ()))
>
> and a lot more familiar to folks knowing C++ (and probably doesn't make
> a difference to others).
>
> Thus, please re-use or follow existing concepts.

Agree. dyn_cast<..> for try casting, and cast<..> or gcc_cast<..>
casting with assertion sounds good.


>
> As for the example with tree we'd then have
>
>   if ((q = dyn_cast <INTEGER_CST> (p)))
>
> if we can overload on the template parameter kind (can we? typename vs. enum?)
> or use tree_cast <> (no I don't want dyn_cast <tree_common> all around the
> code).

yes, that also sounds good to me.

thanks,

David

>
> Thanks,
> Richard.
>
>>
>> thanks,
>>
>> David
>>
>>
>>>
>>> --
>>> Lawrence Crowl
Lawrence Crowl - Oct. 13, 2012, 5:44 p.m.
On 10/12/12, Richard Biener <richard.guenther@gmail.com> wrote:
> On Oct 11, 2012 Xinliang David Li <davidxl@google.com> wrote:
>> On Oct 11, 2012 Lawrence Crowl <crowl@googlers.com> wrote:
>>> On 10/10/12, Xinliang David Li <davidxl@google.com> wrote:
>>>> In a different thread, I proposed the following alternative to
>>>> 'try_xxx':
>>>>
>>>> template<typename T> T* symbol::cast_to(symbol* p) {
>>>>    if (p->is<T>())
>>>>       return static_cast<T*>(p);
>>>>    return 0;
>>>>  }
>>>>
>>>> cast:
>>>>
>>>> template<typename T> T& symbol:as(symbol* p) {
>>>>    assert(p->is<T>())
>>>>    return static_cast<T&>(*p);
>>>>
>>>>  }
>>>
>>> My concern here was never the technical feasibility, nor the
>>> desirability of having the facility for generic code, but the amount
>>> of the amount of typing in non-generic contexts.  That is
>>>
>>>   if (cgraph_node *q = p->try_function ())
>>>
>>> versus
>>>
>>>   if (cgraph_node *q = p->cast_to <cgraph_node *> ())
>>>
>>> I thought the latter would generate objections.  Does anyone object
>>> to the extra typing?
>>>
>>> If not, I can make that change.
>>
>> Think about a more complex class hierarchy and interface consistency.
>> I believe you don't want this:
>>
>> tree::try_decl () { .. }
>> tree::try_ssa_name () { ..}
>> tree::try_type() {...}
>> tree::try_int_const () {..}
>> tree::try_exp () { ...}
>>  ..
>>
>> Rather one (or two with the const_cast version).
>>
>> template <T> T *tree::cast_to ()
>> {
>>    if (kind_ == kind_traits<T>::value)
>>     return static_cast<T*> (this);
>>
>>  return 0;
>> }
>
> I also think that instead of
>
>>>   if (cgraph_node *q = p->cast_to <cgraph_node *> ())
>
> we want
>
>   if ((q = cast_to <cgraph_node *> (p))
>
> I see absolutely no good reason to make cast_to a member, given
> that the language has static_cast, const_cast and stuff.  cast_to
> would simply be our equivalent to dynamic_cast within our OO model.

Sorry, that was a think-o.  Agreed there is no point in it being a
member.

> Then I'd call it *_cast instead of cast_*, so, why not gcc_cast < >?
> Or dyn_cast <> ().  That way
>
>   if ((q = dyn_cast <function *> (p))
>
> would be how to use it.

Which function?  The point with my original proposal is that the
kind of function was derivable from context, and thus can be shorter.

> Small enough, compared to
>
>   if ((q = p->try_function ()))
>
> and a lot more familiar to folks knowing C++ (and probably doesn't
> make a difference to others).
>
> Thus, please re-use or follow existing concepts.

Both are existing concepts.  What I proposed is a common technique
for avoiding the cost of dynamic_cast when down casting in a class
hierarchy.  Both concepts will work.  I proposed what I thought
would be most convenient to programmers.  However, I will change
to the other form unless someone objects.

> As for the example with tree we'd then have
>
>   if ((q = dyn_cast <INTEGER_CST> (p)))
>
> if we can overload on the template parameter kind (can we?
> typename vs.  enum?)

There are two template parameters, one for the argument type and
one for the return type.  We can overload on the argument type but
not on the return type.  We can, however, (indirectly) partially
specialize on the return type.  We need to do that anyway to
represent the fact that not all type conversions are legal.

However, I recommend against specializing on the enum, as it would
become somewhat obscure when the hierarchy is discriminated on more
than one enum.

> or use tree_cast <> (no I don't want dyn_cast <tree_common>
> all around the code).

Once we have proper class hierarchies, derived to base conversions
are implicit.  In the meantime, we need something else.
Gabriel Dos Reis - Oct. 13, 2012, 5:56 p.m.
On Sat, Oct 13, 2012 at 12:44 PM, Lawrence Crowl <crowl@googlers.com> wrote:

>> Thus, please re-use or follow existing concepts.
>
> Both are existing concepts.  What I proposed is a common technique
> for avoiding the cost of dynamic_cast when down casting in a class
> hierarchy.  Both concepts will work.  I proposed what I thought
> would be most convenient to programmers.  However, I will change
> to the other form unless someone objects.

Let me elaborate on your point.

The concept you are trying to implement is that of:
   (a) check whether a tree is of a certain kind;
   (b) if so return a pointer to the (sub-)object of that kind;
         otherwise a null pointer.

This is a standard idiom -- at least when using C++.

It can be implemented in various ways.  Your earlier attempt
try_xxx is one example.  Another common example, built into
the language is dynamic_cast.  The latter requires that classes
involved in this test be polymorphic (because the builtin implementation
needs to consult metadata that are already present with virtual
functions.)  Yet, another implementation is what is currently in GCC
more-or-less.

I think we should name the operation based on the abstract concept
we are implementing as opposed the builtin language implementation.
That is why I recommend is<> over dyn_cast<> or variations of it.

We should be able to understand its uses without having to know
the implementation details.


> However, I recommend against specializing on the enum, as it would
> become somewhat obscure when the hierarchy is discriminated on more
> than one enum.

100% agreed.

-- Gaby
Diego Novillo - Oct. 14, 2012, 3:15 p.m.
On Fri, Oct 12, 2012 at 4:22 AM, Richard Biener
<richard.guenther@gmail.com> wrote:

> I also think that instead of
>
>>>   if (cgraph_node *q = p->cast_to <cgraph_node *> ())
>
> we want
>
>   if ((q = cast_to <cgraph_node *> (p))
>
> I see absolutely no good reason to make cast_to a member, given
> that the language has static_cast, const_cast and stuff.  cast_to
> would simply be our equivalent to dynamic_cast within our OO model.
>
> Then I'd call it *_cast instead of cast_*, so, why not gcc_cast < >?
> Or dyn_cast <> ().  That way
>
>   if ((q = dyn_cast <function *> (p))

This looks fine to me.


Diego.

Patch

Index: gcc/ChangeLog

2012-09-18  Lawrence Crowl  <crowl@google.com

	* cgraph.h (varpool_node): Rename to varpool_node_for_tree.
	Adjust callers to match.
	(symtab_node_def::try_function): New.
	Change most calls to symtab_function_p with calls to
	symtab_node_def::try_function.
	(symtab_node_def::try_variable): New.
	Change most calls to symtab_variable_p with calls to
	symtab_node_def::try_variable.
	(symtab_function_p): Rename to symtab_node_def::is_function.
	Adjust remaining callers to match.
	(symtab_variable_p): Rename to symtab_node_def::is_variable.
	Adjust remaining callers to match.
	* cgraph.c (cgraph_node_for_asm): Remove redundant call to
	symtab_node_for_asm.
	* graphunit.c (symbol_finalized_and_needed): New.
	(symbol_finalized): New.
	(cgraph_analyze_functions): Split complicated conditionals out into
	above new functions.


Index: gcc/lto-symtab.c
===================================================================
--- gcc/lto-symtab.c	(revision 191403)
+++ gcc/lto-symtab.c	(working copy)
@@ -743,7 +743,7 @@  lto_symtab_merge_cgraph_nodes_1 (void **
 	{
 	  if (!prevailing->vnode)
 	    {
-	      prevailing->vnode = varpool_node (prevailing->decl);
+	      prevailing->vnode = varpool_node_for_tree (prevailing->decl);
 	      prevailing->vnode->alias = true;
 	    }
 	  lto_varpool_replace_node (e->vnode, prevailing->vnode);
Index: gcc/cgraphbuild.c
===================================================================
--- gcc/cgraphbuild.c	(revision 191403)
+++ 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_tree (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_tree (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_tree (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_tree (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_tree (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_tree (decl);
   struct record_reference_ctx ctx = {false, NULL};

   ctx.varpool_node = node;
Index: gcc/cgraph.c
===================================================================
--- gcc/cgraph.c	(revision 191403)
+++ gcc/cgraph.c	(working copy)
@@ -506,9 +506,10 @@  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 (; node; node = node->symbol.next_sharing_asm_name)
+    if (cgraph_node *cn = node->try_function ())
+      if (!cn->global.inlined_to)
+	return cn;
   return NULL;
 }

Index: gcc/cgraph.h
===================================================================
--- gcc/cgraph.h	(revision 191403)
+++ gcc/cgraph.h	(working copy)
@@ -448,13 +448,46 @@  struct GTY(()) asm_node {
 /* Symbol table entry.  */
 union GTY((desc ("%h.symbol.type"), chain_next ("%h.symbol.next"),
 	   chain_prev ("%h.symbol.previous"))) symtab_node_def {
+  /* Dynamic type testers. */
+  bool GTY((skip)) is_function ();
+  bool GTY((skip)) is_variable ();
+  /* Conditional accessors return null if not the requested type.  */
+  cgraph_node * GTY((skip)) try_function ();
+  varpool_node * GTY((skip)) try_variable ();
+
   struct symtab_node_base GTY ((tag ("SYMTAB_SYMBOL"))) symbol;
-  /* Use cgraph (symbol) accessor to get cgraph_node.  */
+  /* To access the following fields,
+     use the conditional accessors try_function and try_variable above
+     or the asserting accessor functions cgraph and varpool.  */
   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;
 };

+inline bool
+symtab_node_def::is_function ()
+{
+  return symbol.type == SYMTAB_FUNCTION;
+}
+
+inline bool
+symtab_node_def::is_variable ()
+{
+  return symbol.type == SYMTAB_VARIABLE;
+}
+
+inline cgraph_node *
+symtab_node_def::try_function ()
+{
+  return is_function () ? &x_function : NULL;
+}
+
+inline varpool_node *
+symtab_node_def::try_variable()
+{
+  return is_variable () ? &x_variable : NULL;
+}
+
+
 extern GTY(()) symtab_node symtab_nodes;
 extern GTY(()) int cgraph_n_nodes;
 extern GTY(()) int cgraph_max_uid;
@@ -677,7 +710,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_tree (tree);
 struct varpool_node *varpool_node_for_asm (tree asmname);
 void varpool_mark_needed_node (struct varpool_node *);
 void debug_varpool (void);
@@ -705,19 +738,6 @@  bool varpool_for_node_and_aliases (struc
 			           void *, bool);
 void varpool_add_new_variable (tree);

-/* 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 *
@@ -791,8 +811,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 = node->try_variable ())
+	return vnode;
     }
   return NULL;
 }
@@ -804,8 +824,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 = node1->try_variable ())
+	return vnode1;
     }
   return NULL;
 }
@@ -822,9 +842,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);
+      if (varpool_node *vnode = node->try_variable ())
+	if (DECL_INITIAL (node->symbol.decl))
+	  return vnode;
     }
   return NULL;
 }
@@ -836,9 +856,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);
+      if (varpool_node *vnode1 = node1->try_variable ())
+	if (DECL_INITIAL (node1->symbol.decl))
+	  return vnode1;
     }
   return NULL;
 }
@@ -855,8 +875,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);
+      if (varpool_node *vnode = node->try_variable ())
+	if (vnode->analyzed)
+	  return vnode;
     }
   return NULL;
 }
@@ -868,8 +889,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);
+      if (varpool_node *vnode1 = node1->try_variable ())
+	if (vnode1->analyzed)
+	  return vnode1;
     }
   return NULL;
 }
@@ -885,8 +907,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);
+      if (cgraph_node *cn = node->try_function ())
+	if (cn->analyzed)
+	  return cn;
     }
   return NULL;
 }
@@ -898,8 +921,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);
+      if (cgraph_node *cn1 = node1->try_function ())
+	if (cn1->analyzed)
+	  return cn1;
     }
   return NULL;
 }
@@ -916,8 +940,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 = node->try_function ())
+	return cn;
     }
   return NULL;
 }
@@ -929,8 +953,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 = node1->try_function ())
+	return cn1;
     }
   return NULL;
 }
@@ -958,9 +982,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);
+      if (cgraph_node *cn = node->try_function ())
+	if (cgraph_function_with_gimple_body_p (cn))
+	  return cn;
     }
   return NULL;
 }
@@ -972,9 +996,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);
+      if (cgraph_node *cn1 = node1->try_function ())
+	if (cgraph_function_with_gimple_body_p (cn1))
+	  return cn1;
     }
   return NULL;
 }
@@ -1173,7 +1197,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 (ref->referred->is_function ())
     return ipa_ref_node (ref);
   return NULL;
 }
@@ -1187,7 +1211,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 (ref->referred->is_variable ())
     return ipa_ref_varpool_node (ref);
   return NULL;
 }
Index: gcc/tree-emutls.c
===================================================================
--- gcc/tree-emutls.c	(revision 191403)
+++ 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_tree (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_tree (to);
   else if (!alias_of)
     varpool_add_new_variable (to);
   else
Index: gcc/ipa-reference.c
===================================================================
--- gcc/ipa-reference.c	(revision 191403)
+++ 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 (!ref->referred->is_variable ())
 	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,29 +992,31 @@  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))
-	  && referenced_from_this_partition_p (&vnode->symbol.ref_list, encoder))
+      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
+      if (varpool_node *vnode = snode->try_variable ())
 	{
-	  tree decl = vnode->symbol.decl;
-	  bitmap_set_bit (ltrans_statics, DECL_UID (decl));
-	  splay_tree_insert (reference_vars_to_consider,
-			     DECL_UID (decl), (splay_tree_value)decl);
-	  ltrans_statics_bitcount ++;
+	  if (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;
+	      bitmap_set_bit (ltrans_statics, DECL_UID (decl));
+	      splay_tree_insert (reference_vars_to_consider,
+				 DECL_UID (decl), (splay_tree_value)decl);
+	      ltrans_statics_bitcount ++;
+	    }
 	}
     }


   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))
-	  count++;
+      {
+	symtab_node snode = lto_symtab_encoder_deref (encoder, i);
+	if (cgraph_node *cnode = snode->try_function ())
+	  if (write_node_summary_p (cnode, encoder, ltrans_statics))
+	    count++;
+      }

   streamer_write_uhwi_stream (ob->main_stream, count);
   if (count)
@@ -1027,24 +1027,22 @@  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))
-	  {
-	    ipa_reference_optimization_summary_t info;
-	    int node_ref;
+	symtab_node snode = lto_symtab_encoder_deref (encoder, i);
+	if (cgraph_node *cnode = snode->try_function ())
+	  if (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);
-	    streamer_write_uhwi_stream (ob->main_stream, node_ref);
+	      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,
-			       ltrans_statics_bitcount);
-	    stream_out_bitmap (ob, info->statics_not_written, ltrans_statics,
-			       ltrans_statics_bitcount);
-	  }
+	      stream_out_bitmap (ob, info->statics_not_read, ltrans_statics,
+			         ltrans_statics_bitcount);
+	      stream_out_bitmap (ob, info->statics_not_written, ltrans_statics,
+			         ltrans_statics_bitcount);
+	    }
       }
   BITMAP_FREE (ltrans_statics);
   lto_destroy_simple_output_block (ob);
Index: gcc/cgraphunit.c
===================================================================
--- gcc/cgraphunit.c	(revision 191403)
+++ gcc/cgraphunit.c	(working copy)
@@ -388,8 +388,9 @@  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)
-    return true;
+  if (cgraph_node *cn = node->try_function ())
+    if (cn->callers)
+      return true;
   return false;
 }

@@ -818,7 +819,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_tree (decl);

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

@@ -845,6 +846,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 = node->try_function ())
+    return cnode->local.finalized
+	   && cgraph_decide_is_function_needed (cnode, cnode->symbol.decl);
+  if (varpool_node *vnode = node->try_variable ())
+    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= node->try_function ())
+    return cnode->local.finalized;
+  if (varpool_node *vnode = node->try_variable ())
+    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  */

@@ -879,13 +909,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)
@@ -912,49 +936,50 @@  cgraph_analyze_functions (void)
 	  changed = true;
 	  node = first;
 	  first = (symtab_node)first->symbol.aux;
-	  if (symtab_function_p (node) && cgraph (node)->local.finalized)
+	  if (cgraph_node *cnode = node->try_function ())
 	    {
-	      struct cgraph_edge *edge;
-	      struct cgraph_node *cnode;
-	      tree decl;
-
-	      cnode = cgraph (node);
-	      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  */
-	      if (!DECL_STRUCT_FUNCTION (decl)
-		  && (!cnode->alias || !cnode->thunk.alias)
-		  && !cnode->thunk.thunk_p)
+	      if (cnode->local.finalized)
 		{
-		  cgraph_reset_node (cnode);
-		  cnode->local.redefined_extern_inline = true;
-		  continue;
-		}
+		  struct cgraph_edge *edge;
+		  tree decl = cnode->symbol.decl;

-	      if (!cnode->analyzed)
-		cgraph_analyze_function (cnode);
+		  /* ??? 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)
+		    {
+		      cgraph_reset_node (cnode);
+		      cnode->local.redefined_extern_inline = true;
+		      continue;
+		    }

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

-	      /* 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));
-		  origin_node->abstract_and_needed = true;
-		}
+		  for (edge = cnode->callees; edge; edge = edge->next_callee)
+		    if (edge->callee->local.finalized)
+		       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_ABSTRACT_ORIGIN (decl))
+		    {
+		      struct cgraph_node *origin_node
+			  = cgraph_get_node (DECL_ABSTRACT_ORIGIN (decl));
+		      origin_node->abstract_and_needed = true;
+		    }
+		}
+	    }
+	  else
+	    {
+	      if (varpool_node *vnode = node->try_variable ())
+		if (vnode->finalized)
+		  varpool_analyze_node (vnode);
 	    }
-	  else if (symtab_variable_p (node)
-		   && varpool (node)->finalized)
-	    varpool_analyze_node (varpool (node));

 	  if (node->symbol.same_comdat_group)
 	    {
@@ -965,9 +990,9 @@  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 ();
 	}
     }
@@ -994,10 +1019,9 @@  cgraph_analyze_functions (void)
 	  symtab_remove_node (node);
 	  continue;
 	}
-      if (symtab_function_p (node))
+      if (cgraph_node *cnode = node->try_function ())
 	{
 	  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)
@@ -1079,7 +1103,7 @@  handle_alias_pairs (void)
 	}

       if (TREE_CODE (p->decl) == FUNCTION_DECL
-          && target_node && symtab_function_p (target_node))
+          && target_node && target_node->is_function ())
 	{
 	  struct cgraph_node *src_node = cgraph_get_node (p->decl);
 	  if (src_node && src_node->local.finalized)
@@ -1088,7 +1112,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 && target_node->is_variable ())
 	{
 	  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 191403)
+++ gcc/cp/decl2.c	(working copy)
@@ -1773,7 +1773,7 @@  import_export_class (tree ctype)
 static bool
 var_finalized_p (tree var)
 {
-  return varpool_node (var)->finalized;
+  return varpool_node_for_tree (var)->finalized;
 }

 /* DECL is a VAR_DECL or FUNCTION_DECL which, for whatever reason,
@@ -1891,7 +1891,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_tree (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 191403)
+++ 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 || referring_node->is_function ());
   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 191403)
+++ gcc/lto-cgraph.c	(working copy)
@@ -665,7 +665,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 (ref->referred->is_function ())
       add_node_to (encoder, ipa_ref_node (ref), false);
     else
       {
@@ -719,9 +719,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 = node->try_variable ())
 	{
-	  struct varpool_node *vnode = varpool (node);
 	  if (DECL_INITIAL (vnode->symbol.decl)
 	      && !lto_symtab_encoder_encode_initializer_p (encoder,
 							   vnode)
@@ -785,8 +784,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 = node->try_function ())
+        lto_output_node (ob, cnode, encoder);
       else
         lto_output_varpool_node (ob, varpool (node), encoder);
 	
@@ -972,7 +971,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_tree (var_decl);
   node->symbol.order = order;
   if (order >= symtab_order)
     symtab_order = order + 1;
@@ -1133,14 +1132,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 || !node->is_function ());
 #endif
   FOR_EACH_VEC_ELT (symtab_node, nodes, i, node)
     {
       int ref;
-      if (symtab_function_p (node))
+      if (cgraph_node *cnode = node->try_function ())
 	{
-	  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)
@@ -1149,9 +1148,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;
@@ -1163,7 +1162,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 = node->is_function () ? (void *)1 : NULL;
   return nodes;
 }

@@ -1437,7 +1436,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);
@@ -1447,19 +1445,22 @@  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);
+      if (cgraph_node *cnode = node->try_function ())
+	if (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)))
-	{
-	  streamer_write_uhwi (ob, i);
-	  output_node_opt_summary (ob, cgraph (node), encoder);
-	}
+      symtab_node node = lto_symtab_encoder_deref (encoder, i);
+      if (cgraph_node *cnode = node->try_function ())
+	if (output_cgraph_opt_summary_p (cnode))
+	  {
+	    streamer_write_uhwi (ob, i);
+	    output_node_opt_summary (ob, cnode, encoder);
+	  }
     }
   produce_asm (ob, NULL);
   destroy_output_block (ob);
Index: gcc/lto-streamer-out.c
===================================================================
--- gcc/lto-streamer-out.c	(revision 191403)
+++ gcc/lto-streamer-out.c	(working copy)
@@ -975,7 +975,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 ();
@@ -991,27 +990,25 @@  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)
-	  && !node->alias
-	  && !node->thunk.thunk_p)
-	{
+      if (cgraph_node *node = snode->try_function ())
+	if (lto_symtab_encoder_encode_body_p (encoder, node)
+	    && !node->alias
+	    && !node->thunk.thunk_p)
+	  {
 #ifdef ENABLE_CHECKING
-	  gcc_assert (!bitmap_bit_p (output, DECL_UID (node->symbol.decl)));
-	  bitmap_set_bit (output, DECL_UID (node->symbol.decl));
+	    gcc_assert (!bitmap_bit_p (output, DECL_UID (node->symbol.decl)));
+	    bitmap_set_bit (output, DECL_UID (node->symbol.decl));
 #endif
-	  decl_state = lto_new_out_decl_state ();
-	  lto_push_out_decl_state (decl_state);
-	  if (gimple_has_body_p (node->symbol.decl))
-	    output_function (node);
-	  else
-	    copy_function (node);
-	  gcc_assert (lto_get_out_decl_state () == decl_state);
-	  lto_pop_out_decl_state ();
-	  lto_record_function_out_decl_state (node->symbol.decl, decl_state);
-	}
+	    decl_state = lto_new_out_decl_state ();
+	    lto_push_out_decl_state (decl_state);
+	    if (gimple_has_body_p (node->symbol.decl))
+	      output_function (node);
+	    else
+	      copy_function (node);
+	    gcc_assert (lto_get_out_decl_state () == decl_state);
+	    lto_pop_out_decl_state ();
+	    lto_record_function_out_decl_state (node->symbol.decl, decl_state);
+	  }
     }

   /* Emit the callgraph after emitting function bodies.  This needs to
@@ -1288,8 +1285,6 @@  produce_symtab (struct output_block *ob)
   struct streamer_tree_cache_d *cache = ob->writer_cache;
   char *section_name = lto_get_section_name (LTO_section_symtab, NULL, NULL);
   struct pointer_set_t *seen;
-  struct cgraph_node *node;
-  struct varpool_node *vnode;
   struct lto_output_stream stream;
   lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
   int i;
@@ -1305,73 +1300,77 @@  produce_symtab (struct output_block *ob)
      This is done so only to handle duplicated symbols in cgraph.  */
   for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
     {
-      if (!symtab_function_p (lto_symtab_encoder_deref (encoder, i)))
-	continue;
-      node = cgraph (lto_symtab_encoder_deref (encoder, i));
-      if (DECL_EXTERNAL (node->symbol.decl))
-	continue;
-      if (DECL_COMDAT (node->symbol.decl)
-	  && cgraph_comdat_can_be_unshared_p (node))
-	continue;
-      if ((node->alias && !node->thunk.alias) || node->global.inlined_to)
-	continue;
-      write_symbol (cache, &stream, node->symbol.decl, seen, false);
+      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
+      if (cgraph_node *cnode = snode->try_function ())
+	{
+	  if (DECL_EXTERNAL (cnode->symbol.decl))
+	    continue;
+	  if (DECL_COMDAT (cnode->symbol.decl)
+	      && cgraph_comdat_can_be_unshared_p (cnode))
+	    continue;
+	  if ((cnode->alias && !cnode->thunk.alias) || cnode->global.inlined_to)
+	    continue;
+	  write_symbol (cache, &stream, cnode->symbol.decl, seen, false);
+	}
     }
   for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
     {
-      if (!symtab_function_p (lto_symtab_encoder_deref (encoder, i)))
-	continue;
-      node = cgraph (lto_symtab_encoder_deref (encoder, i));
-      if (!DECL_EXTERNAL (node->symbol.decl))
-	continue;
-      /* We keep around unused extern inlines in order to be able to inline
-	 them indirectly or via vtables.  Do not output them to symbol
-	 table: they end up being undefined and just consume space.  */
-      if (!node->symbol.address_taken && !node->callers)
-	continue;
-      if (DECL_COMDAT (node->symbol.decl)
-	  && cgraph_comdat_can_be_unshared_p (node))
-	continue;
-      if ((node->alias && !node->thunk.alias) || node->global.inlined_to)
-	continue;
-      write_symbol (cache, &stream, node->symbol.decl, seen, false);
+      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
+      if (cgraph_node *cnode = snode->try_function ())
+	{
+	  if (!DECL_EXTERNAL (cnode->symbol.decl))
+	    continue;
+	  /* We keep around unused extern inlines in order to be able to inline
+	     them indirectly or via vtables.  Do not output them to symbol
+	     table: they end up being undefined and just consume space.  */
+	  if (!cnode->symbol.address_taken && !cnode->callers)
+	    continue;
+	  if (DECL_COMDAT (cnode->symbol.decl)
+	      && cgraph_comdat_can_be_unshared_p (cnode))
+	    continue;
+	  if ((cnode->alias && !cnode->thunk.alias) || cnode->global.inlined_to)
+	    continue;
+	  write_symbol (cache, &stream, cnode->symbol.decl, seen, false);
+	}
     }

   /* Write all variables.  */
   for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
     {
-      if (!symtab_variable_p (lto_symtab_encoder_deref (encoder, i)))
-	continue;
-      vnode = varpool (lto_symtab_encoder_deref (encoder, i));
-      if (DECL_EXTERNAL (vnode->symbol.decl))
-	continue;
-      /* COMDAT virtual tables can be unshared.  Do not declare them
-	 in the LTO symbol table to prevent linker from forcing them
-	 into the output. */
-      if (DECL_COMDAT (vnode->symbol.decl)
-	  && !vnode->symbol.force_output
-	  && vnode->finalized
-	  && DECL_VIRTUAL_P (vnode->symbol.decl))
-	continue;
-      if (vnode->alias && !vnode->alias_of)
-	continue;
-      write_symbol (cache, &stream, vnode->symbol.decl, seen, false);
+      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
+      if (varpool_node *vnode = snode->try_variable ())
+	{
+	  if (DECL_EXTERNAL (vnode->symbol.decl))
+	    continue;
+	  /* COMDAT virtual tables can be unshared.  Do not declare them
+	     in the LTO symbol table to prevent linker from forcing them
+	     into the output. */
+	  if (DECL_COMDAT (vnode->symbol.decl)
+	      && !vnode->symbol.force_output
+	      && vnode->finalized
+	      && DECL_VIRTUAL_P (vnode->symbol.decl))
+	    continue;
+	  if (vnode->alias && !vnode->alias_of)
+	    continue;
+	  write_symbol (cache, &stream, vnode->symbol.decl, seen, false);
+	}
     }
   for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
     {
-      if (!symtab_variable_p (lto_symtab_encoder_deref (encoder, i)))
-	continue;
-      vnode = varpool (lto_symtab_encoder_deref (encoder, i));
-      if (!DECL_EXTERNAL (vnode->symbol.decl))
-	continue;
-      if (DECL_COMDAT (vnode->symbol.decl)
-	  && !vnode->symbol.force_output
-	  && vnode->finalized
-	  && DECL_VIRTUAL_P (vnode->symbol.decl))
-	continue;
-      if (vnode->alias && !vnode->alias_of)
-	continue;
-      write_symbol (cache, &stream, vnode->symbol.decl, seen, false);
+      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
+      if (varpool_node *vnode = snode->try_variable ())
+	{
+	  if (!DECL_EXTERNAL (vnode->symbol.decl))
+	    continue;
+	  if (DECL_COMDAT (vnode->symbol.decl)
+	      && !vnode->symbol.force_output
+	      && vnode->finalized
+	      && DECL_VIRTUAL_P (vnode->symbol.decl))
+	    continue;
+	  if (vnode->alias && !vnode->alias_of)
+	    continue;
+	  write_symbol (cache, &stream, vnode->symbol.decl, seen, false);
+	}
     }

   lto_write_stream (&stream);
Index: gcc/ada/gcc-interface/utils.c
===================================================================
--- gcc/ada/gcc-interface/utils.c	(revision 191403)
+++ gcc/ada/gcc-interface/utils.c	(working copy)
@@ -5582,7 +5582,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_tree (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 191403)
+++ 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 (ref->referred->is_function ())
 	{
 	  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 = node->try_function ())
 	{
-	  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)
@@ -331,19 +329,21 @@  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)
-	  && DECL_EXTERNAL (node->symbol.decl)
-	  && !varpool (node)->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++)
-	    enqueue_node (ref->referred, &first, reachable);
-        }
+      /* When we see constructor of external variable, keep referred nodes
+	 in the boundary.  This will also hold initializers of the external
+	 vars NODE refers to.  */
+      if (varpool_node *vnode = node->try_variable ())
+	if (DECL_EXTERNAL (node->symbol.decl)
+	    && !vnode->alias
+	    && in_boundary_p)
+	  {
+	    struct ipa_ref *ref;
+	    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 +526,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 (ref->referring->is_function ())
 	  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 191403)
+++ gcc/ipa-inline-analysis.c	(working copy)
@@ -3816,65 +3816,68 @@  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);
+      if (cgraph_node *cnode = snode->try_function ())
+	if (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)
-	{
-	  struct inline_summary *info = inline_summary (node);
-	  struct bitpack_d bp;
-	  struct cgraph_edge *edge;
-	  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);
-	  streamer_write_hwi (ob, info->self_time);
-	  bp = bitpack_create (ob->main_stream);
-	  bp_pack_value (&bp, info->inlinable, 1);
-	  streamer_write_bitpack (&bp);
-	  streamer_write_uhwi (ob, VEC_length (condition, info->conds));
-	  for (i = 0; VEC_iterate (condition, info->conds, i, c); i++)
-	    {
-	      streamer_write_uhwi (ob, c->operand_num);
-	      streamer_write_uhwi (ob, c->code);
-	      stream_write_tree (ob, c->val, true);
-	      bp = bitpack_create (ob->main_stream);
-	      bp_pack_value (&bp, c->agg_contents, 1);
-	      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, VEC_length (size_time_entry, info->entry));
-	  for (i = 0;
-	       VEC_iterate (size_time_entry, info->entry, i, e);
-	       i++)
-	    {
-	      streamer_write_uhwi (ob, e->size);
-	      streamer_write_uhwi (ob, e->time);
-	      write_predicate (ob, &e->predicate);
-	    }
-	  write_predicate (ob, info->loop_iterations);
-	  write_predicate (ob, info->loop_stride);
-	  for (edge = node->callees; edge; edge = edge->next_callee)
-	    write_inline_edge_summary (ob, edge);
-	  for (edge = node->indirect_calls; edge; edge = edge->next_callee)
-	    write_inline_edge_summary (ob, edge);
+      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
+      if (cgraph_node *cnode = snode->try_function ())
+	if ((node = cnode)->analyzed)
+	  {
+	    struct inline_summary *info = inline_summary (node);
+	    struct bitpack_d bp;
+	    struct cgraph_edge *edge;
+	    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);
+	    streamer_write_hwi (ob, info->self_time);
+	    bp = bitpack_create (ob->main_stream);
+	    bp_pack_value (&bp, info->inlinable, 1);
+	    streamer_write_bitpack (&bp);
+	    streamer_write_uhwi (ob, VEC_length (condition, info->conds));
+	    for (i = 0; VEC_iterate (condition, info->conds, i, c); i++)
+	      {
+		streamer_write_uhwi (ob, c->operand_num);
+		streamer_write_uhwi (ob, c->code);
+		stream_write_tree (ob, c->val, true);
+		bp = bitpack_create (ob->main_stream);
+		bp_pack_value (&bp, c->agg_contents, 1);
+		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, VEC_length (size_time_entry, info->entry));
+	    for (i = 0;
+		 VEC_iterate (size_time_entry, info->entry, i, e);
+		 i++)
+	      {
+		streamer_write_uhwi (ob, e->size);
+		streamer_write_uhwi (ob, e->time);
+		write_predicate (ob, &e->predicate);
+	      }
+	    write_predicate (ob, info->loop_iterations);
+	    write_predicate (ob, info->loop_stride);
+	    for (edge = node->callees; edge; edge = edge->next_callee)
+	      write_inline_edge_summary (ob, edge);
+	    for (edge = node->indirect_calls; edge; edge = edge->next_callee)
+	      write_inline_edge_summary (ob, edge);
 	}
     }
   streamer_write_char_stream (ob->main_stream, 0);
Index: gcc/lto/lto.c
===================================================================
--- gcc/lto/lto.c	(revision 191403)
+++ gcc/lto/lto.c	(working copy)
@@ -2619,12 +2619,16 @@  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)))
-		    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)");
+		  if (cgraph_node *cnode = node->try_function ())
+		    {
+		      if (lto_symtab_encoder_encode_body_p (part->encoder, cnode))
+		      fprintf (cgraph_dump_file, "(body included)");
+		    }
+		  else if (varpool_node *vnode = node->try_variable ())
+		    {
+		      if (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 191403)
+++ 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)
-    return SYMBOL_DUPLICATE;
+  if (cgraph_node *cnode = node->try_function ())
+    if (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 = node->try_variable ())
     {
       /* 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 (ref->referred->is_variable ()
 	     && 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 = node->try_function ())
     {
-      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 = node->try_function ())
     {
-      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 = node->try_variable ())
+    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 = node->try_function ())
+        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 = snode->try_function ())
 	    {
 	      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 (ref->referred->is_variable ())
 	      {
 		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 (ref->referring->is_variable ())
 	      {
 		int index;

Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c	(revision 191403)
+++ 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_tree (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_tree (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 191403)
+++ gcc/symtab.c	(working copy)
@@ -239,8 +239,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 = node->try_function ())
+	replacement_node = (symtab_node)cgraph_find_replacement_node (cnode);
       if (!replacement_node)
 	htab_clear_slot (symtab_hash, slot);
       else
@@ -281,10 +281,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 = node->try_function ())
+    cgraph_remove_node (cnode);
+  else if (varpool_node *vnode = node->try_variable ())
+    varpool_remove_node (vnode);
 }

 /* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME.
@@ -514,10 +514,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 = node->try_function ())
+    dump_cgraph_node (f, cnode);
+  else if (varpool_node *vnode = node->try_variable ())
+    dump_varpool_node (f, vnode);
 }

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

-  if (symtab_function_p (node))
+  if (node->is_function ())
     {
       if (TREE_CODE (node->symbol.decl) != FUNCTION_DECL)
 	{
@@ -563,7 +563,7 @@  verify_symtab_base (symtab_node node)
           error_found = true;
 	}
     }
-  else if (symtab_variable_p (node))
+  else if (node->is_variable ())
     {
       if (TREE_CODE (node->symbol.decl) != VAR_DECL)
 	{
@@ -651,8 +651,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 = node->try_function ())
+    verify_cgraph_node (cnode);
   else
     if (verify_symtab_base (node))
       {
Index: gcc/passes.c
===================================================================
--- gcc/passes.c	(revision 191403)
+++ 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_tree (decl);
 }

 /* Called after finishing a record, union or enumeral type.  */
Index: gcc/varpool.c
===================================================================
--- gcc/varpool.c	(revision 191403)
+++ 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_tree (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 = node->try_variable ())
+      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_tree (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_tree (node->alias_of);
       struct varpool_node *n;

       for (n = tgt; n && n->alias;
@@ -374,16 +374,15 @@  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);
+	    if (varpool_node *vnext = next->try_variable ())
+	      if (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);
+	if (varpool_node *vnode = ref->referred->try_variable ())
+	  if ((!DECL_EXTERNAL (ref->referred->symbol.decl) || vnode->alias)
+	      && vnode->analyzed)
+	    enqueue_node (vnode, &first);
     }
   if (cgraph_dump_file)
     fprintf (cgraph_dump_file, "\nRemoving variables:");
@@ -457,7 +456,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_tree (new_decl);
   varpool_finalize_decl (new_decl);

   return new_node->symbol.decl;
@@ -473,7 +472,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_tree (alias);
   alias_node->alias = 1;
   alias_node->finalized = 1;
   alias_node->alias_of = decl;
Index: gcc/lto-streamer.h
===================================================================
--- gcc/lto-streamer.h	(revision 191403)
+++ gcc/lto-streamer.h	(working copy)
@@ -1121,7 +1121,7 @@  lsei_next_function_in_partition (lto_sym
 {
   lsei_next (lsei);
   while (!lsei_end_p (*lsei)
-	 && (!symtab_function_p (lsei_node (*lsei))
+	 && (!lsei_node (*lsei)->is_function ()
 	     || !lto_symtab_encoder_in_partition_p (lsei->encoder, lsei_node
(*lsei))))
     lsei_next (lsei);