summaryrefslogtreecommitdiff
path: root/gcc/collect-types.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/collect-types.c')
-rw-r--r--gcc/collect-types.c422
1 files changed, 422 insertions, 0 deletions
diff --git a/gcc/collect-types.c b/gcc/collect-types.c
new file mode 100644
index 00000000000..0ce6cccb025
--- /dev/null
+++ b/gcc/collect-types.c
@@ -0,0 +1,422 @@
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple-expr.h"
+#include "predict.h"
+#include "alloc-pool.h"
+#include "tree-pass.h"
+#include "cgraph.h"
+#include "diagnostic.h"
+#include "fold-const.h"
+#include "gimple-fold.h"
+#include "symbol-summary.h"
+#include "tree-vrp.h"
+#include "ipa-prop.h"
+#include "tree-pretty-print.h"
+#include "tree-inline.h"
+#include "ipa-fnsummary.h"
+#include "ipa-utils.h"
+#include "tree-ssa-ccp.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "tree-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+
+#include "compare-types.h"
+#include "types-inlines.h"
+#include "name-types.h"
+#include <set>
+
+#include "collect-types.h"
+
+static bool filter_boring_types(const_tree type, ptrset_t &);
+
+static bool
+filter_boring_types_wrapper(const_tree type, ptrset_t &types)
+{
+ gcc_assert(type);
+ const_tree inner_type = TREE_TYPE(type);
+ gcc_assert(inner_type);
+ return filter_boring_types(inner_type, types);
+}
+
+static bool
+filter_boring_types_array(const_tree type, ptrset_t &types)
+{
+ assert_is_type(type, ARRAY_TYPE);
+ return filter_boring_types_wrapper(type, types);
+}
+
+static bool
+filter_boring_types_reference(const_tree type, ptrset_t &types)
+{
+ assert_is_type(type, REFERENCE_TYPE);
+ return filter_boring_types_wrapper(type, types);
+}
+
+static bool
+filter_boring_types_pointer(const_tree type, ptrset_t &types)
+{
+ assert_is_type(type, POINTER_TYPE);
+ return filter_boring_types_wrapper(type, types);
+}
+
+static bool
+filter_boring_types_record(const_tree type, ptrset_t &types)
+{
+ assert_is_type(type, RECORD_TYPE);
+ return false;
+}
+
+static bool
+filter_boring_types_unions(const_tree type, ptrset_t &types)
+{
+ const enum tree_code code = TREE_CODE(type);
+ const bool is_union = UNION_TYPE == code;
+ const bool is_qual_union = QUAL_UNION_TYPE == code;
+ const bool is_valid_input = is_union || is_qual_union;
+ gcc_assert(is_valid_input);
+
+ for (tree field = TYPE_FIELDS(type) ; field ; field = DECL_CHAIN(field))
+ {
+ const_tree field_type = TREE_TYPE(field);
+ gcc_assert(field_type);
+ const bool is_boring = filter_boring_types(field_type, types);
+ if (!is_boring) return is_boring;
+ }
+
+ return true;
+}
+
+static bool
+filter_boring_types_union(const_tree type, ptrset_t &types)
+{
+ assert_is_type(type, UNION_TYPE);
+ return filter_boring_types_unions(type, types);
+}
+
+static bool
+filter_boring_types_qual_union(const_tree type, ptrset_t &types)
+{
+ assert_is_type(type, QUAL_UNION_TYPE);
+ return filter_boring_types_unions(type, types);
+}
+
+static bool
+filter_boring_types_function_or_method(const_tree type, ptrset_t &types)
+{
+ const enum tree_code code = TREE_CODE(type);
+ const bool is_function = FUNCTION_TYPE == code;
+ const bool is_method = METHOD_TYPE == code;
+ const bool is_valid_input = is_function || is_method;
+ gcc_assert(is_valid_input);
+
+ const_tree ret_type = TREE_TYPE(type);
+ gcc_assert(ret_type);
+ const bool retval_is_boring = filter_boring_types(ret_type, types);
+ if (!retval_is_boring) return retval_is_boring;
+
+ tree arg_node = TYPE_ARG_TYPES(type);
+ while (NULL_TREE != arg_node)
+ {
+ tree arg_node_type = TREE_VALUE(arg_node);
+ gcc_assert(arg_node_type);
+ const bool arg_is_boring = filter_boring_types(arg_node_type, types);
+ arg_node = TREE_CHAIN(arg_node);
+ if (!arg_is_boring) return arg_is_boring;
+ }
+
+ return true;
+}
+
+static bool
+filter_boring_types_function(const_tree type, ptrset_t &types)
+{
+ assert_is_type(type, FUNCTION_TYPE);
+ return filter_boring_types_function_or_method(type, types);
+}
+
+static bool
+filter_boring_types_method(const_tree type, ptrset_t &types)
+{
+ assert_is_type(type, METHOD_TYPE);
+ return filter_boring_types_function_or_method(type, types);
+}
+
+static bool
+filter_boring_types(const_tree type, ptrset_t &types)
+{
+ // boring types are those that do not point to
+ // a struct
+ gcc_assert(type);
+
+ // Optimization to speed up the filter.
+ // Memoization
+ const bool seen_before = types.in_universe(type);
+ if (seen_before)
+ {
+ const bool in_points_to_record = types.in_points_to_record(type);
+ const bool in_complement = types.in_complement(type);
+ const bool _xor = in_points_to_record != in_complement;
+ gcc_assert(_xor);
+ return in_complement;
+ }
+
+
+ bool is_boring = true;
+ enum tree_code code = TREE_CODE(type);
+ switch (code)
+ {
+ case ARRAY_TYPE:
+ is_boring = filter_boring_types_array(type, types);
+ break;
+ case RECORD_TYPE:
+ is_boring = filter_boring_types_record(type, types);
+ break;
+ case UNION_TYPE:
+ is_boring = filter_boring_types_union(type, types);
+ break;
+ case QUAL_UNION_TYPE:
+ is_boring = filter_boring_types_qual_union(type, types);
+ break;
+ case REFERENCE_TYPE:
+ is_boring = filter_boring_types_reference(type, types);
+ break;
+ case POINTER_TYPE:
+ is_boring = filter_boring_types_pointer(type, types);
+ break;
+ case FUNCTION_TYPE:
+ is_boring = filter_boring_types_function(type, types);
+ break;
+ case METHOD_TYPE:
+ is_boring = filter_boring_types_method(type, types);
+ break;
+ default:
+ // I will probably need to fuzz.
+ break;
+ }
+
+ // This should be one the two only times we call insert!
+ types.insert(type, !is_boring);
+
+ return is_boring;
+}
+
+static const unsigned filter_buffer_size = 1;
+typedef bool (*filter_t)(const_tree, ptrset_t&);
+const extern filter_t filter[filter_buffer_size] =
+{
+ filter_boring_types,
+};
+
+static void
+collect_types_from_record_or_union_type(const_tree type, ptrset_t &types)
+{
+ gcc_assert(type);
+ const enum tree_code code = TREE_CODE(type);
+ const bool is_union = UNION_TYPE == code;
+ const bool is_record = RECORD_TYPE == code;
+ const bool is_valid_input = is_union || is_record;
+ gcc_assert(is_valid_input);
+
+ for (tree field = TYPE_FIELDS(type) ; field ; field = DECL_CHAIN(field))
+ {
+ const_tree field_type = TREE_TYPE(field);
+ gcc_assert(field_type);
+ collect_types(field_type, types);
+ }
+}
+
+static void
+collect_types_from_record_type(const_tree type, ptrset_t &types)
+{
+ assert_is_type(type, RECORD_TYPE);
+ collect_types_from_record_or_union_type(type, types);
+}
+
+static void
+collect_types_from_union_type(const_tree type, ptrset_t &types)
+{
+ assert_is_type(type, UNION_TYPE);
+ collect_types_from_record_or_union_type(type, types);
+}
+
+static void
+collect_types_from_wrapper_type(const_tree type, ptrset_t &types)
+{
+ gcc_assert(type);
+ const_tree inner_type = TREE_TYPE(type);
+ gcc_assert(inner_type);
+ collect_types(inner_type, types);
+}
+
+static void
+collect_types_from_pointer_type(const_tree type, ptrset_t &types)
+{
+ assert_is_type(type, POINTER_TYPE);
+ collect_types_from_wrapper_type(type, types);
+}
+
+static void
+collect_types_from_reference_type(const_tree type, ptrset_t &types)
+{
+ assert_is_type(type, REFERENCE_TYPE);
+ collect_types_from_wrapper_type(type, types);
+}
+
+static void
+collect_types_from_array_type(const_tree type, ptrset_t &types)
+{
+ assert_is_type(type, ARRAY_TYPE);
+ collect_types_from_wrapper_type(type, types);
+}
+
+static void
+collect_types_from_function_or_method_type(const_tree type, ptrset_t &types)
+{
+ gcc_assert(type);
+ const enum tree_code code = TREE_CODE(type);
+ const bool is_function = FUNCTION_TYPE == code;
+ const bool is_method = METHOD_TYPE == code;
+ const bool is_valid_input = is_function || is_method;
+ gcc_assert(is_valid_input);
+
+ const_tree ret_type = TREE_TYPE(type);
+ gcc_assert(ret_type);
+ collect_types(ret_type, types);
+
+ tree arg_node = TYPE_ARG_TYPES(type);
+ while (NULL_TREE != arg_node)
+ {
+ tree arg_node_type = TREE_VALUE(arg_node);
+ gcc_assert(arg_node_type);
+ collect_types(arg_node_type, types);
+ arg_node = TREE_CHAIN(arg_node);
+ }
+}
+
+static void
+collect_types_from_function_type(const_tree type, ptrset_t &types)
+{
+ assert_is_type(type, FUNCTION_TYPE);
+ collect_types_from_function_or_method_type(type, types);
+}
+
+static void
+collect_types_from_method_type(const_tree type, ptrset_t &types)
+{
+ assert_is_type(type, METHOD_TYPE);
+ collect_types_from_function_or_method_type(type, types);
+}
+
+void
+points_to_record_sets_s::insert(const_tree type, bool in_points_to_record)
+{
+ gcc_assert(type);
+ this->universe.insert(type);
+ in_points_to_record ? this->points_to_record.insert(type) : this->complement.insert(type);
+ // let's just double check...
+ const bool in_points_to_set = this->in_points_to_record(type);
+ const bool in_complement = this->in_complement(type);
+ const bool _xor = in_points_to_set != in_complement;
+ gcc_assert(_xor);
+}
+
+bool
+points_to_record_sets_s::in_universe(const_tree type) const
+{
+ gcc_assert(type);
+ const bool seen_before = this->universe.find(type) != this->universe.end();
+ return seen_before;
+}
+
+bool
+points_to_record_sets_s::in_points_to_record(const_tree type) const
+{
+ gcc_assert(type);
+ const bool seen_before = this->points_to_record.find(type) != this->points_to_record.end();
+ return seen_before;
+}
+
+bool
+points_to_record_sets_s::in_complement(const_tree type) const
+{
+ gcc_assert(type);
+ const bool seen_before = this->complement.find(type) != this->complement.end();
+ return seen_before;
+}
+
+void
+collect_types(const_tree type, ptrset_t &types)
+{
+ if (!type) return;
+
+ // This should be the only case we call to find if
+ // we have seen the type before!
+ const bool in_set = types.in_universe(type);
+ // memoized.
+ if (in_set) return;
+
+ // we should have filters here
+ // such that if we are processing a type
+ // which we know somehow that it is not a type we are interested
+ // then we just return immediately.
+ // maybe even add it to a set of blacklisted types so that we
+ // memoize and do things faster...
+ bool is_boring = false;
+ for (unsigned i = 0; i < filter_buffer_size; i++)
+ {
+ is_boring |= filter[i](type, types);
+ }
+
+ const enum tree_code code = TREE_CODE(type);
+ switch (code)
+ {
+ case VOID_TYPE:
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case FIXED_POINT_TYPE:
+ case COMPLEX_TYPE:
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case OFFSET_TYPE:
+ // simple cases and we want to allow them
+ break;
+ case RECORD_TYPE:
+ collect_types_from_record_type(type, types);
+ break;
+ case POINTER_TYPE:
+ collect_types_from_pointer_type(type, types);
+ break;
+ case REFERENCE_TYPE:
+ collect_types_from_reference_type(type, types);
+ break;
+ case ARRAY_TYPE:
+ collect_types_from_array_type(type, types);
+ break;
+ case UNION_TYPE:
+ collect_types_from_union_type(type, types);
+ break;
+ case FUNCTION_TYPE:
+ collect_types_from_function_type(type, types);
+ break;
+ case METHOD_TYPE:
+ collect_types_from_method_type(type, types);
+ break;
+ case QUAL_UNION_TYPE:
+ case LANG_TYPE:
+ default:
+ log("%s\n", get_tree_code_name(code));
+ gcc_unreachable();
+ break;
+ }
+
+ // This should be one the two only times we call insert!
+ types.insert(type, !is_boring);
+}