aboutsummaryrefslogtreecommitdiff
path: root/gcc/is-a.h
diff options
context:
space:
mode:
authorLawrence Crowl <crowl@google.com>2012-10-31 23:15:10 +0000
committerLawrence Crowl <crowl@gcc.gnu.org>2012-10-31 23:15:10 +0000
commit5d59b5e18a878c2201471e529c40f15d49905fc8 (patch)
tree7209857044c64b9be2543946aeb701d483464efa /gcc/is-a.h
parent2a381a57f3061e171923a14083ac37d957c9c98d (diff)
downloadgcc-5d59b5e18a878c2201471e529c40f15d49905fc8.zip
gcc-5d59b5e18a878c2201471e529c40f15d49905fc8.tar.gz
gcc-5d59b5e18a878c2201471e529c40f15d49905fc8.tar.bz2
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. From-SVN: r193051
Diffstat (limited to 'gcc/is-a.h')
-rw-r--r--gcc/is-a.h201
1 files changed, 201 insertions, 0 deletions
diff --git a/gcc/is-a.h b/gcc/is-a.h
new file mode 100644
index 0000000..c5c75b4
--- /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 */