diff options
author | crowl <crowl@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-10-31 23:15:10 +0000 |
---|---|---|
committer | crowl <crowl@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-10-31 23:15:10 +0000 |
commit | 2dc9831fc1c17840efc629788027aeededa44d2f (patch) | |
tree | 7209857044c64b9be2543946aeb701d483464efa /gcc/is-a.h | |
parent | e98dcfc2367b0800142ab02aaee07d1407ff51a3 (diff) | |
download | gcc-2dc9831fc1c17840efc629788027aeededa44d2f.tar.gz |
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.
Index: gcc/ChangeLog
2012-10-31 Lawrence Crowl <crowl@google.com>
* is-a.h: New.
(is_a <T> (U*)): New. Test for is-a relationship.
(as_a <T> (U*)): New. Treat as a derived type.
(dyn_cast <T> (U*)): New. Conditionally cast based on is_a.
* cgraph.h (varpool_node): Rename to varpool_node_for_decl.
Adjust callers to match.
(is_a_helper <cgraph_node>::test (symtab_node_def *)): New.
(is_a_helper <varpool_node>::test (symtab_node_def *)): New.
(symtab_node_def::try_function): New. Change most calls to
symtab_function_p with calls to dyn_cast <cgraph_node> (p).
(symtab_node_def::try_variable): New. Change most calls to
symtab_variable_p with calls to dyn_cast <varpool_node> (p).
(symtab_function_p): Remove. Change callers to use
is_a <cgraph_node> (p) instead.
(symtab_variable_p): Remove. Change callers to use
is_a <varpool_node> (p) instead.
* cgraph.c (cgraph_node_for_asm): Remove redundant call to
symtab_node_for_asm.
* cgraphunit.c (symbol_finalized_and_needed): New.
(symbol_finalized): New.
(cgraph_analyze_functions): Split complicated conditionals out into
above new functions.
* Makefile.in (CGRAPH_H): Add is-a.h as used by cgraph.h.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@193051 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/is-a.h')
-rw-r--r-- | gcc/is-a.h | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/gcc/is-a.h b/gcc/is-a.h new file mode 100644 index 00000000000..c5c75b4bc87 --- /dev/null +++ b/gcc/is-a.h @@ -0,0 +1,201 @@ +/* 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/>. */ + + +/* This header generic type query and conversion functions. + + +USING THE GENERIC TYPE FACILITY + + +The user functions are: + +bool is_a <TYPE> (pointer) + + Tests whether the pointer actually points to a more derived TYPE. + + 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)) + .... + + +TYPE *as_a <TYPE> (pointer) + + Converts pointer to a TYPE*. + + You can just assume that it is such a node. + + do_something_with (as_a <cgraph_node> *ptr); + +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. + + This functions reduce compile time and increase type safety when treating a + generic item as a more specific item. + + You can test and obtain a pointer to the 'derived' type in one indivisible + operation. + + if (cgraph_node *cptr = dyn_cast <cgraph_node> (ptr)) + .... + + As an example, 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 approach + 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. + + +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. See below. + + +EXTENDING THE GENERIC TYPE FACILITY + +Each connection between types must be made by defining a specialization of the +template member function 'test' of the template class 'is_a_helper'. For +example, + + 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 pointer types is incorrect, then you +must also specialize the template member function 'cast'. Failure to do so +when needed may result in a crash. For example, + + template <> + template <> + inline bool + is_a_helper <cgraph_node>::cast (symtab_node_def *p) + { + return &p->x_function; + } + +*/ + +#ifndef GCC_IS_A_H +#define GCC_IS_A_H + +/* A generic type conversion internal helper class. */ + +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); +}; + +/* Note that we deliberately do not define the 'test' member template. Not + doing so will result in a build-time error for type relationships that have + not been defined, rather than a run-time error. See the discussion above + for when to define this member. */ + +/* This is the generic implementation for casting from one type to another. + Do not use this routine directly; it is an internal function. See the + discussion above for when to define this member. */ + +template <typename T> +template <typename U> +inline T * +is_a_helper <T>::cast (U *p) +{ + return reinterpret_cast <T *> (p); +} + + +/* The public interface. */ + +/* A generic test for a type relationship. See the discussion above for when + to use this function. The question answered is "Is type T a derived type of + type U?". */ + +template <typename T, typename U> +inline bool +is_a (U *p) +{ + return is_a_helper<T>::test (p); +} + +/* A generic conversion from a base type U to a derived type T. See the + discussion above for when to use this function. */ + +template <typename T, typename U> +inline T * +as_a (U *p) +{ + gcc_assert (is_a <T> (p)); + return is_a_helper <T>::cast (p); +} + +/* A generic checked conversion from a base type U to a derived type T. See + the discussion above for when to use this function. */ + +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 */ |