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