summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErick Ochoa <erick.ochoa@theobroma-systems.com>2020-05-14 14:48:22 +0200
committerErick Ochoa <erick.ochoa@theobroma-systems.com>2020-05-14 14:48:22 +0200
commitcf730672e416091269ef355bd4a8be5cf2a23785 (patch)
tree5c68343de00c674213e714e81eb7782869a4dc78
parent5e74c695ff9bef9ba000884c1d7e2b8762e90fc3 (diff)
parenta22362346872039fa01a22fc8dc2c26de16d24a0 (diff)
Merge branch 'erick/type-escape-analysis-refactor' into erick/type-escape-analysis-merge
-rwxr-xr-xbuild.sh15
-rw-r--r--gcc/Makefile.in4
-rw-r--r--gcc/collect-types.c422
-rw-r--r--gcc/collect-types.h19
-rw-r--r--gcc/common.opt10
-rw-r--r--gcc/compare-types.c457
-rw-r--r--gcc/compare-types.h11
-rw-r--r--gcc/gimple.h28
-rw-r--r--gcc/ipa-escape-analysis.c821
-rw-r--r--gcc/name-types.c420
-rw-r--r--gcc/name-types.h11
-rw-r--r--gcc/passes.def1
-rw-r--r--gcc/testsuite/gcc.dg/ipa/type-playground-00.c21
-rw-r--r--gcc/testsuite/gcc.dg/ipa/type-playground-01.c19
-rw-r--r--gcc/testsuite/gcc.dg/ipa/type-playground-02.c19
-rw-r--r--gcc/testsuite/gcc.dg/ipa/type-playground-03.c25
-rw-r--r--gcc/testsuite/gcc.dg/ipa/type-playground-04.c25
-rw-r--r--gcc/tree-pass.h1
-rw-r--r--gcc/types-inlines.h37
19 files changed, 2350 insertions, 16 deletions
diff --git a/build.sh b/build.sh
index 97158b0cf59..620573c7b68 100755
--- a/build.sh
+++ b/build.sh
@@ -3,16 +3,11 @@
set -e
set -u
-installdir=${1:-"gcc-inst"}
-mkdir -p $HOME/code/gcc-build/
-mkdir -p $HOME/code/${installdir}/
-pushd $HOME/code/gcc-build/
-if find . -mindepth 1 -print -quit 2>/dev/null | grep -q . ; then
- echo "not empty?"
-else
- $OLDPWD/configure --disable-bootstrap --disable-libsanitizer --enable-__cxa_atexit --enable-shared --disable-libsanitizer --enable-languages=c,c++,fortran --enable-lto --enable-gold --enable-linker-build-id --with-cpu-emag --prefix="$HOME/code/${installdir}/"
-fi
-
+suffix=${1:-""}
+mkdir -p $HOME/code/gcc-build${suffix}/
+mkdir -p $HOME/code/gcc-inst${suffix}/
+pushd $HOME/code/gcc-build${suffix}/
+$OLDPWD/configure --disable-bootstrap --disable-libsanitizer --enable-__cxa_atexit --enable-shared --disable-libsanitizer --enable-languages=c,c++,fortran --enable-lto --enable-gold --enable-linker-build-id --with-cpu-emag --prefix="$HOME/code/gcc-inst${suffix}/"
make -j `nproc`
make install -j `nproc`
make check-gcc RUNTESTFLAGS="ipa.exp"
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 082d48a496d..419f64ec70e 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1405,6 +1405,10 @@ OBJS = \
internal-fn.o \
ipa-type-escape-analysis.o \
ipa-hello-world.o \
+ ipa-escape-analysis.o \
+ compare-types.o \
+ collect-types.o \
+ name-types.o \
ipa-cp.o \
ipa-sra.o \
ipa-devirt.o \
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);
+}
diff --git a/gcc/collect-types.h b/gcc/collect-types.h
new file mode 100644
index 00000000000..883c08d36dc
--- /dev/null
+++ b/gcc/collect-types.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "tree.h"
+#include <set>
+
+typedef std::set<const_tree> typeset;
+struct points_to_record_sets_s {
+ typeset universe;
+ typeset points_to_record;
+ typeset complement;
+ bool in_universe(const_tree) const;
+ bool in_points_to_record(const_tree) const;
+ bool in_complement(const_tree) const;
+ void insert(const_tree, bool);
+};
+
+typedef struct points_to_record_sets_s ptrset_t;
+
+extern void collect_types(const_tree type, ptrset_t &ptrset_t);
diff --git a/gcc/common.opt b/gcc/common.opt
index 4aca7c9547a..86aeb0d39e7 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3445,4 +3445,14 @@ fipa-hello-world
Common Report Var(flag_ipa_hello_world) Optimization
Hello world
+fipa-escape-analysis
+Common Report Var(flag_ipa_escape_analysis) Optimization
+TBD
+
+ftp-types-compared=
+Common Joined Report Var(flag_tp_types_compared) Init(0)
+
+ftp-comparison-functions=
+Common Joined Report Var(flag_tp_comparison_functions) Init(0)
+
; This comment is to ensure we retain the blank line above.
diff --git a/gcc/compare-types.c b/gcc/compare-types.c
new file mode 100644
index 00000000000..4be9d28151d
--- /dev/null
+++ b/gcc/compare-types.c
@@ -0,0 +1,457 @@
+#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"
+
+static bool
+is_incomplete_type(const_tree a)
+{
+ gcc_assert(a);
+ const_tree type_size = TYPE_SIZE(a);
+ return NULL_TREE == type_size;
+}
+
+bool
+eq_main_variant(const_tree a, const_tree b)
+{
+ gcc_assert(a && b);
+ const_tree main_variant_a = TYPE_MAIN_VARIANT(a);
+ const_tree main_variant_b = TYPE_MAIN_VARIANT(b);
+ gcc_assert(main_variant_a && main_variant_b);
+ const bool are_equal = main_variant_a == main_variant_b;
+ return are_equal;
+}
+
+bool
+eq_canonical_internal(const_tree a, const_tree b)
+{
+ gcc_assert(a && b);
+ const_tree canonical_a = TYPE_CANONICAL(a);
+ const_tree canonical_b = TYPE_CANONICAL(b);
+ const bool are_equal = canonical_a == canonical_b;
+ return are_equal;
+}
+
+static bool
+eq_record_or_union_types(const_tree a, const_tree b, const bool force_structural)
+{
+ gcc_assert(a && b);
+
+ tree field_a = TYPE_FIELDS(a);
+ tree field_b = TYPE_FIELDS(b);
+ while (field_a || field_b)
+ {
+ const bool different_lengths = (bool)field_a != (bool)field_b;
+ if (different_lengths) return false;
+
+ const_tree field_type_a = TREE_TYPE(field_a);
+ const_tree field_type_b = TREE_TYPE(field_b);
+ gcc_assert(field_type_a && field_type_b);
+ const bool same_field_types = eq_types(field_type_a, field_type_b, force_structural);
+ if (!same_field_types) return false;
+
+ field_a = DECL_CHAIN(field_a);
+ field_b = DECL_CHAIN(field_b);
+ }
+
+ return true;
+}
+
+static bool
+eq_record_types(const_tree a, const_tree b, const bool force_structural)
+{
+ gcc_assert(a && b);
+ assert_is_type(a, RECORD_TYPE);
+ assert_is_type(b, RECORD_TYPE);
+ return eq_record_or_union_types(a, b, force_structural);
+}
+
+static bool
+eq_union_types(const_tree a, const_tree b, const bool force_structural)
+{
+ gcc_assert(a && b);
+ assert_is_type(a, UNION_TYPE);
+ assert_is_type(b, UNION_TYPE);
+ return eq_record_or_union_types(a, b, force_structural);
+}
+
+static bool
+eq_wrapper_types(const_tree a, const_tree b, const bool force_structural)
+{
+ gcc_assert(a && b);
+ const_tree inner_type_a = TREE_TYPE(a);
+ const_tree inner_type_b = TREE_TYPE(b);
+ gcc_assert(inner_type_a && inner_type_b);
+ return eq_types(inner_type_a, inner_type_b, force_structural);
+}
+
+static bool
+eq_pointer_types(const_tree a, const_tree b, const bool force_structural)
+{
+ gcc_assert(a && b);
+ assert_is_type(a, POINTER_TYPE);
+ assert_is_type(b, POINTER_TYPE);
+ return eq_wrapper_types(a, b, force_structural);
+}
+
+static bool
+eq_reference_types(const_tree a, const_tree b, const bool force_structural)
+{
+ gcc_assert(a && b);
+ assert_is_type(a, REFERENCE_TYPE);
+ assert_is_type(b, REFERENCE_TYPE);
+ return eq_wrapper_types(a, b, force_structural);
+}
+
+static bool
+eq_array_types(const_tree a, const_tree b, const bool force_structural)
+{
+ gcc_assert(a && b);
+ assert_is_type(a, ARRAY_TYPE);
+ assert_is_type(b, ARRAY_TYPE);
+ return eq_wrapper_types(a, b, force_structural);
+}
+
+static bool
+eq_function_or_method_types(const_tree a, const_tree b, const bool force_structural)
+{
+ gcc_assert(a && b);
+ const_tree return_type_a = TREE_TYPE(a);
+ const_tree return_type_b = TREE_TYPE(b);
+ const bool is_return_equal = eq_types(return_type_a, return_type_b, force_structural);
+ if (!is_return_equal) return false;
+
+ tree parm_a = TYPE_ARG_TYPES(a);
+ tree parm_b = TYPE_ARG_TYPES(b);
+
+ while (parm_a || parm_b)
+ {
+ const bool different_lengths = (bool)parm_a != (bool)parm_b;
+ if (different_lengths) return false;
+
+ const_tree parm_type_a = TREE_VALUE(parm_a);
+ const_tree parm_type_b = TREE_VALUE(parm_b);
+ gcc_assert(parm_type_a && parm_type_b);
+ const bool same_field_types = eq_types(parm_type_a, parm_type_b, force_structural);
+ if (!same_field_types) return false;
+
+ parm_a = TREE_CHAIN(parm_a);
+ parm_b = TREE_CHAIN(parm_b);
+ }
+
+ return true;
+}
+
+static bool
+eq_function_types(const_tree a, const_tree b, const bool force_structural)
+{
+ gcc_assert(a && b);
+ assert_is_type(a, FUNCTION_TYPE);
+ assert_is_type(b, FUNCTION_TYPE);
+ return eq_function_or_method_types(a, b, force_structural);
+}
+
+static bool
+eq_method_types(const_tree a, const_tree b, const bool force_structural)
+{
+ gcc_assert(a && b);
+ assert_is_type(a, METHOD_TYPE);
+ assert_is_type(b, METHOD_TYPE);
+
+ const_tree base_type_a = TYPE_METHOD_BASETYPE(a);
+ const_tree base_type_b = TYPE_METHOD_BASETYPE(b);
+ const bool eq_base_types = eq_types(base_type_a, base_type_b, force_structural);
+ return eq_base_types && eq_function_or_method_types(a, b, force_structural);
+}
+
+static bool eq_structural(const_tree a, const_tree b, const bool force_structural = false);
+
+bool
+eq_pointer(const_tree a, const_tree b)
+{
+ return a == b;
+}
+
+bool
+eq_identifier(const_tree a, const_tree b)
+{
+ std::string name_a = get_type_identifier(a);
+ std::string name_b = get_type_identifier(b);
+ return name_a.compare(name_b) == 0;
+}
+
+static bool
+eq_structural(const_tree a, const_tree b, const bool force_structural)
+{
+ gcc_assert(a && b);
+ const enum tree_code code_a = TREE_CODE(a);
+ const enum tree_code code_b = TREE_CODE(b);
+ const bool equal_code = code_a == code_b;
+ if (!equal_code) return false;
+
+ const enum tree_code code = code_a;
+ switch (code)
+ {
+ //FIXME: Just because two codes are the same
+ //doesn't mean they are the same type
+ //E.g. short != int
+ // float != double
+ // enum a != enum b
+ 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:
+ return true;
+ break;
+ default:
+ break;
+ }
+
+ switch (code)
+ {
+ case RECORD_TYPE:
+ return eq_record_types(a, b, force_structural);
+ break;
+ case POINTER_TYPE:
+ return eq_pointer_types(a, b, force_structural);
+ break;
+ case REFERENCE_TYPE:
+ return eq_reference_types(a, b, force_structural);
+ break;
+ case ARRAY_TYPE:
+ return eq_array_types(a, b, force_structural);
+ break;
+ case UNION_TYPE:
+ return eq_union_types(a, b, force_structural);
+ break;
+ case FUNCTION_TYPE:
+ return eq_function_types(a, b, force_structural);
+ break;
+ case METHOD_TYPE:
+ return eq_method_types(a, b, force_structural);
+ break;
+ case QUAL_UNION_TYPE:
+ case LANG_TYPE:
+ default:
+ // Unimplemented
+ gcc_unreachable();
+ break;
+ }
+
+ gcc_unreachable();
+ return false;
+}
+
+bool
+eq_canonical(const_tree a, const_tree b)
+{
+ gcc_assert(a && b);
+ const bool struct_eq_a = TYPE_STRUCTURAL_EQUALITY_P(a);
+ const bool struct_eq_b = TYPE_STRUCTURAL_EQUALITY_P(b);
+ const bool use_structural_equality = struct_eq_a || struct_eq_b;
+ const bool are_equal = use_structural_equality ? eq_structural(a, b) : eq_canonical_internal(a, b);
+ return are_equal;
+}
+
+
+bool
+eq_type_compare(const_tree a, const_tree b)
+{
+ return eq_types(a, b);
+}
+
+bool
+eq_type_structural(const_tree a, const_tree b)
+{
+ return eq_types(a, b, true);
+}
+
+bool
+eq_types(const_tree a, const_tree b, const bool force_structural)
+{
+ gcc_assert(a && b);
+ // This should be before comparing incomplete types.
+ // This is not enabled by default, and it is used for
+ // testing structural equality limitations.
+ if (force_structural) return eq_structural(a, b, force_structural);
+
+ // eq_structural (a-incomplete, a-complete) = false
+ // eq_main_variant(a-incomplete, a-complete) = false
+ // eq_canonical (a-incomplete, a-complete) = false
+ // Fallback to eq_identifier only here.
+ // This should be the only static call to eq_identifier!
+ const bool is_a_incomplete = is_incomplete_type(a);
+ const bool is_b_incomplete = is_incomplete_type(b);
+ const bool compare_incomplete_types = is_a_incomplete || is_b_incomplete;
+ if (compare_incomplete_types) return eq_identifier(a, b);
+
+
+ if (eq_main_variant(a, b)) return true;
+
+ if (!eq_canonical(a, b)) return false;
+
+ // optimistic...
+ // maybe we should have a MAYBE?
+ //gcc_unreachable();
+ return false;
+}
+
+namespace test_type_equality {
+
+static void
+test_main_variant()
+{
+ tree void_a = make_node(VOID_TYPE);
+ tree void_b = build_variant_type_copy(void_a);
+ const bool expected = true;
+ const bool observed = eq_types(void_a, void_b);
+ const bool success = expected == observed;
+ gcc_assert(success);
+}
+
+static void
+test_pointer_types_eq()
+{
+ tree pointer_a = make_node(POINTER_TYPE);
+ tree inner_type = make_node(INTEGER_TYPE);
+ TREE_TYPE(pointer_a) = inner_type;
+ tree pointer_b = build_variant_type_copy(pointer_a);
+ const bool expected = true;
+ const bool observed = eq_types(pointer_a, pointer_b);
+ const bool success = expected == observed;
+ gcc_assert(success);
+}
+
+static void
+test_pointer_types_ne()
+{
+ tree pointer_a = make_node(POINTER_TYPE);
+ tree inner_type_a = make_node(INTEGER_TYPE);
+ TREE_TYPE(pointer_a) = inner_type_a;
+ tree pointer_b = make_node(POINTER_TYPE);
+ tree inner_type_b = make_node(VOID_TYPE);
+ TREE_TYPE(pointer_b) = inner_type_b;
+ const bool expected = false;
+ const bool observed = eq_types(pointer_a, pointer_b, true);
+ const bool success = expected == observed;
+ gcc_assert(success);
+}
+
+static void
+test_pointer_types_eq_structurally()
+{
+ tree pointer_a = make_node(POINTER_TYPE);
+ tree inner_type_a = make_node(INTEGER_TYPE);
+ TREE_TYPE(pointer_a) = inner_type_a;
+ tree pointer_b = make_node(POINTER_TYPE);
+ tree inner_type_b = make_node(INTEGER_TYPE);
+ TREE_TYPE(pointer_b) = inner_type_b;
+ const bool expected = true;
+ const bool observed = eq_types(pointer_a, pointer_b, true);
+ const bool success = expected == observed;
+ gcc_assert(success);
+}
+
+static void
+test_void_eq()
+{
+ tree void_a = make_node(VOID_TYPE);
+ tree void_b = build_variant_type_copy(void_a);
+ const bool expected = true;
+ const bool observed = eq_types(void_a, void_b, true);
+ const bool success = expected == observed;
+ gcc_assert(success);
+}
+
+static void
+test_structural_equality_different_types()
+{
+ tree type_a = make_node(VOID_TYPE);
+ tree type_b = make_node(RECORD_TYPE);
+ const bool expected = false;
+ const bool observed = eq_types(type_a, type_b, true);
+ const bool success = expected == observed;
+ gcc_assert(success);
+}
+
+static void
+test_different_record_types()
+{
+ tree type_a = make_node(RECORD_TYPE);
+ tree type_b = make_node(RECORD_TYPE);
+ tree field_a = make_node(FIELD_DECL);
+ tree field_b = make_node(FIELD_DECL);
+ tree type_field_a = make_node(VOID_TYPE);
+ tree type_field_b = make_node(RECORD_TYPE);
+ TREE_TYPE(field_a) = type_field_a;
+ TREE_TYPE(field_b) = type_field_b;
+ TYPE_FIELDS(type_a) = field_a;
+ TYPE_FIELDS(type_b) = field_b;
+ const bool expected = false;
+ const bool observed = eq_types(type_a, type_b, true);
+ const bool success = expected == observed;
+ gcc_assert(success);
+}
+
+static void
+test_same_record_types()
+{
+ tree type_a = make_node(RECORD_TYPE);
+ tree field_a = make_node(FIELD_DECL);
+ tree type_field_a = make_node(VOID_TYPE);
+ TREE_TYPE(field_a) = type_field_a;
+ TYPE_FIELDS(type_a) = field_a;
+ tree type_b = build_variant_type_copy(type_a);
+ const bool expected = true;
+ const bool observed = eq_types(type_a, type_b, true);
+ const bool success = expected == observed;
+ gcc_assert(success);
+}
+
+void
+run_tests()
+{
+ test_main_variant();
+ test_void_eq();
+ test_structural_equality_different_types();
+ test_different_record_types();
+ test_same_record_types();
+ test_pointer_types_eq_structurally();
+ test_pointer_types_ne();
+ test_pointer_types_eq();
+
+}
+} // test_type_equality
diff --git a/gcc/compare-types.h b/gcc/compare-types.h
new file mode 100644
index 00000000000..2c690fc3081
--- /dev/null
+++ b/gcc/compare-types.h
@@ -0,0 +1,11 @@
+#pragma once
+
+namespace test_type_equality { void run_tests(); };
+extern bool eq_identifier(const_tree a, const_tree b);
+extern bool eq_pointer(const_tree a, const_tree b);
+extern bool eq_main_variant(const_tree a, const_tree b);
+extern bool eq_canonical(const_tree a, const_tree b);
+extern bool eq_canonical_internal(const_tree a, const_tree b);
+extern bool eq_type_compare(const_tree a, const_tree b);
+extern bool eq_type_structural(const_tree a, const_tree b);
+extern bool eq_types(const_tree a, const_tree b, const bool force_structural = false);
diff --git a/gcc/gimple.h b/gcc/gimple.h
index ca7fec6247e..e5b594a5b01 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -6494,6 +6494,23 @@ gimple_transaction_set_subcode (gtransaction *transaction_stmt,
transaction_stmt->subcode = subcode;
}
+
+/* Return the return value for GIMPLE_RETURN GS. */
+
+static inline tree
+gimple_return_retval (const greturn *gs)
+{
+ return gs->op[0];
+}
+
+static inline tree
+gimple_return_retval(const gimple *gs)
+{
+ GIMPLE_CHECK(gs, GIMPLE_RETURN);
+ const greturn *gr = dyn_cast<const greturn *> (gs);
+ return gimple_return_retval (gr);
+}
+
/* Return a pointer to the return value for GIMPLE_RETURN GS. */
static inline tree *
@@ -6502,15 +6519,14 @@ gimple_return_retval_ptr (greturn *gs)
return &gs->op[0];
}
-/* Return the return value for GIMPLE_RETURN GS. */
-
-static inline tree
-gimple_return_retval (const greturn *gs)
+static inline tree *
+gimple_return_retval_ptr (gimple *gs)
{
- return gs->op[0];
+ GIMPLE_CHECK(gs, GIMPLE_RETURN);
+ greturn *gr = dyn_cast<greturn *> (gs);
+ return gimple_return_retval_ptr (gr);
}
-
/* Set RETVAL to be the return value for GIMPLE_RETURN GS. */
static inline void
diff --git a/gcc/ipa-escape-analysis.c b/gcc/ipa-escape-analysis.c
new file mode 100644
index 00000000000..04023a406a5
--- /dev/null
+++ b/gcc/ipa-escape-analysis.c
@@ -0,0 +1,821 @@
+#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 <set>
+#include <string>
+
+#include "collect-types.h"
+#include "name-types.h"
+
+//#define FUZZ_MODE 1
+
+namespace type_playground {
+enum type_comparison_func_enum {
+ EQ_POINTER = 0,
+ EQ_IDENTIFIER,
+ EQ_MAIN_VARIANT,
+ EQ_CANONICAL,
+ EQ_STRUCTURAL,
+ EQ_CANONICAL_STRICT,
+ EQ_COMPARE,
+ EQ_END
+};
+static unsigned const type_comparisons = EQ_END;
+static const char* names[type_comparisons] = {
+ "EQ_POINTER",
+ "EQ_IDENTIFIER",
+ "EQ_MAIN_VARIANT",
+ "EQ_CANONICAL",
+ "EQ_CANONICAL_STRICT",
+ "EQ_STRUCTURAL",
+ "EQ_COMPARE"
+};
+typedef bool (*type_comparison_func_t)(const_tree, const_tree);
+static type_comparison_func_t comparisons[type_comparisons] = {
+ eq_pointer,
+ eq_identifier,
+ eq_main_variant,
+ eq_canonical,
+ eq_canonical_internal,
+ eq_type_structural,
+ eq_type_compare
+};
+}
+static void collect_types_from_expr(const_tree expr, ptrset_t &types);
+
+inline void
+is_gimple_code(gimple *stmt, const enum gimple_code ex_code)
+{
+ gcc_assert(stmt);
+ const enum gimple_code ob_code = gimple_code(stmt);
+ const bool succeeds = ex_code == ob_code;
+ gcc_assert(succeeds);
+}
+
+inline void
+is_gimple_rhs_class(gimple *stmt, const enum gimple_rhs_class ex_class)
+{
+ gcc_assert(stmt);
+ is_gimple_code(stmt, GIMPLE_ASSIGN);
+ const enum gimple_rhs_class ob_class = gimple_assign_rhs_class(stmt);
+ const bool succeeds = ex_class == ob_class;
+ gcc_assert(succeeds);
+}
+
+static void
+collect_types_from_op(const_tree expr, ptrset_t &types, unsigned n)
+{
+ gcc_assert(expr);
+ const_tree op_n = TREE_OPERAND(expr, n);
+ gcc_assert(op_n);
+ collect_types_from_expr(op_n, types);
+}
+
+static void
+collect_types_from_op0(const_tree expr, ptrset_t &types, const enum tree_code ex_code)
+{
+ assert_is_type(expr, ex_code);
+ collect_types_from_op(expr, types, 0);
+}
+
+static void
+collect_types_from_op1(const_tree expr, ptrset_t &types, const enum tree_code ex_code)
+{
+ assert_is_type(expr, ex_code);
+ collect_types_from_op(expr, types, 0);
+ collect_types_from_op(expr, types, 1);
+}
+
+static void
+collect_types_from_addr_expr(const_tree expr, ptrset_t &types)
+{
+ collect_types_from_op0(expr, types, ADDR_EXPR);
+}
+
+static void
+collect_types_from_component_ref(const_tree expr, ptrset_t &types)
+{
+ collect_types_from_op1(expr, types, COMPONENT_REF);
+}
+
+static void
+collect_types_from_mem_ref(const_tree expr, ptrset_t &types)
+{
+ collect_types_from_op1(expr, types, MEM_REF);
+}
+
+static void
+collect_types_from_array_ref(const_tree expr, ptrset_t &types)
+{
+ collect_types_from_op1(expr, types, ARRAY_REF);
+}
+
+static void
+collect_types_from_leaf_expr(const_tree expr, ptrset_t &types, const enum tree_code ex_code)
+{
+ assert_is_type(expr, ex_code);
+ const_tree type = TREE_TYPE(expr);
+ gcc_assert(type);
+ collect_types(type, types);
+}
+
+static void
+collect_types_from_ssa_name(const_tree expr, ptrset_t &types)
+{
+ collect_types_from_leaf_expr(expr, types, SSA_NAME);
+}
+
+static void
+collect_types_from_var_decl(const_tree expr, ptrset_t &types)
+{
+ collect_types_from_leaf_expr(expr, types, VAR_DECL);
+}
+
+static void
+collect_types_from_field_decl(const_tree expr, ptrset_t &types)
+{
+ collect_types_from_leaf_expr(expr, types, FIELD_DECL);
+}
+
+static void
+collect_types_from_integer_cst(const_tree expr, ptrset_t &types)
+{
+ collect_types_from_leaf_expr(expr, types, INTEGER_CST);
+}
+
+static void
+collect_types_from_constructor_array(const_tree expr, ptrset_t &types)
+{
+ assert_is_type(expr, CONSTRUCTOR);
+ const_tree type = TREE_TYPE(expr);
+ assert_is_type(type, ARRAY_TYPE);
+ //TODO: Collect types from here
+#ifdef FUZZ_MODE
+ gcc_unreachable();
+#endif
+}
+
+static void
+collect_types_from_constructor_record_or_union(const_tree expr, ptrset_t &types)
+{
+ assert_is_type(expr, CONSTRUCTOR);
+ const_tree type = TREE_TYPE(expr);
+ const enum tree_code code = TREE_CODE(type);
+ const bool is_record = RECORD_TYPE == code;
+ const bool is_union = UNION_TYPE == code;
+ const bool is_qual_union = QUAL_UNION_TYPE == code;
+ const bool is_valid_input = is_record || is_union || is_qual_union;
+ gcc_assert(is_valid_input);
+ //TODO: Collect types from here
+#ifdef FUZZ_MODE
+ gcc_unreachable();
+#endif
+}
+
+static void
+collect_types_from_constructor(const_tree expr, ptrset_t &types)
+{
+ // https://gcc.gnu.org/onlinedocs/gccint/Unary-and-Binary-Expressions.html#Unary-and-Binary-Expressions
+ // These nodes represent the brace-enclosed initializers for a structure or an array.
+ // They contain a sequence of component values made out of a vector of constructor_elt, which is a (INDEX, VALUE) pair.
+ // If the TREE_TYPE of the CONSTRUCTOR is a RECORD_TYPE, UNION_TYPE or QUAL_UNION_TYPE then
+ // the INDEX of each node in the sequence will be a FIELD_DECL and the VALUE will be the expression used to initialize that field.
+ // If the TREE_TYPE of the CONSTRUCTOR is an ARRAY_TYPE, then the INDEX of
+ // each node in the sequence will be an INTEGER_CST or a RANGE_EXPR of
+ // two INTEGER_CSTs. A single INTEGER_CST indicates which element of
+ // the array is being assigned to. A RANGE_EXPR indicates an inclusive range
+ // of elements to initialize. In both cases the VALUE is the
+ // corresponding initializer. It is re-evaluated for each element of
+ // a RANGE_EXPR. If the INDEX is NULL_TREE, then the initializer
+ // is for the next available array element.
+ assert_is_type(expr, CONSTRUCTOR);
+ const_tree type = TREE_TYPE(expr);
+ gcc_assert(type);
+ const enum tree_code code = TREE_CODE(type);
+ switch (code)
+ {
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ case ARRAY_TYPE:
+ break;
+ default:
+ // TODO: I should fuzz this, I got a constructor of an integer type?
+#ifdef FUZZ_MODE
+ gcc_unreachable();
+#endif
+ return;
+ break;
+ }
+
+ const bool is_array = ARRAY_TYPE == code;
+ is_array ? collect_types_from_constructor_array(expr, types) : collect_types_from_constructor_record_or_union(expr, types);
+}
+
+static void
+collect_types_from_parm_decl(const_tree expr, ptrset_t &types)
+{
+ collect_types_from_leaf_expr(expr, types, PARM_DECL);
+}
+
+static void
+collect_types_from_real_cst(const_tree expr, ptrset_t &types)
+{
+ collect_types_from_leaf_expr(expr, types, REAL_CST);
+}
+
+static void
+collect_types_from_string_cst(const_tree expr, ptrset_t &types)
+{
+ collect_types_from_leaf_expr(expr, types, STRING_CST);
+}
+
+static void
+collect_types_from_bit_field_ref(const_tree expr, ptrset_t &types)
+{
+ // TODO: How to collect types from bit_field_ref?
+#ifdef FUZZ_MODE
+ gcc_unreachable();
+#endif
+}
+
+static void
+collect_types_from_view_convert_expr(const_tree expr, ptrset_t &types)
+{
+ // VIEW_CONVERT_EXPR is used to interpret the bit representation
+ // of a register as a register of a different type.
+ // It is unspecified if this is allowed to change the
+ // register size. If disallowed this case needs to go
+ // through an integer mode and an intermediate BIT_FIELD_REF.
+ // https://gcc.gnu.org/wiki/MemRef
+ //TODO: How to collect types from VIEW_CONVERT_EXPR?
+#ifdef FUZZ_MODE
+ gcc_unreachable();
+#endif
+}
+
+static void
+collect_types_from_result_decl(const_tree expr, ptrset_t &types)
+{
+ collect_types_from_leaf_expr(expr, types, RESULT_DECL);
+}
+
+static void
+collect_types_from_expr(const_tree expr, ptrset_t &types)
+{
+ // These are the codes I saw using csmith to fuzz.
+ gcc_assert(expr);
+ const_tree type = TREE_TYPE(expr);
+ gcc_assert(type);
+ collect_types(type, types);
+ const enum tree_code code = TREE_CODE(expr);
+ switch (code)
+ {
+ case ADDR_EXPR:
+ collect_types_from_addr_expr(expr, types);
+ break;
+ case BIT_FIELD_REF:
+ collect_types_from_bit_field_ref(expr, types);
+ break;
+ case ARRAY_REF:
+ collect_types_from_array_ref(expr, types);
+ break;
+ case MEM_REF:
+ collect_types_from_mem_ref(expr, types);
+ break;
+ case COMPONENT_REF:
+ collect_types_from_component_ref(expr, types);
+ break;
+ case SSA_NAME:
+ collect_types_from_ssa_name(expr, types);
+ break;
+ case VAR_DECL:
+ collect_types_from_var_decl(expr, types);
+ break;
+ case FIELD_DECL:
+ collect_types_from_field_decl(expr, types);
+ break;
+ case VIEW_CONVERT_EXPR:
+ collect_types_from_view_convert_expr(expr, types);
+ break;
+ case INTEGER_CST:
+ collect_types_from_integer_cst(expr, types);
+ break;
+ case CONSTRUCTOR:
+ collect_types_from_constructor(expr, types);
+ break;
+ case RESULT_DECL:
+ collect_types_from_result_decl(expr, types);
+ break;
+ case PARM_DECL:
+ collect_types_from_parm_decl(expr, types);
+ break;
+ case REAL_CST:
+ collect_types_from_real_cst(expr, types);
+ break;
+ case STRING_CST:
+ collect_types_from_string_cst(expr, types);
+ break;
+ default:
+ log("tree_code: %s\n", get_tree_code_name(code));
+ gcc_unreachable();
+ break;
+ }
+}
+
+static void
+collect_types_from_stmt_assign_lhs(gimple *stmt, ptrset_t &types)
+{
+ is_gimple_code(stmt, GIMPLE_ASSIGN);
+ const_tree lhs = gimple_assign_lhs(stmt);
+ gcc_assert(lhs);
+ collect_types_from_expr(lhs, types);
+}
+
+static void
+collect_types_from_stmt_assign_rhs3(gimple *stmt, ptrset_t &types)
+{
+ is_gimple_rhs_class(stmt, GIMPLE_TERNARY_RHS);
+ const_tree rhs = gimple_assign_rhs3(stmt);
+ gcc_assert(rhs);
+ collect_types_from_expr(rhs, types);
+}
+
+static void
+collect_types_from_stmt_assign_rhs2(gimple *stmt, ptrset_t &types)
+{
+ is_gimple_code(stmt, GIMPLE_ASSIGN);
+ const enum gimple_rhs_class gclass = gimple_assign_rhs_class(stmt);
+ const bool is_ternary = GIMPLE_TERNARY_RHS == gclass;
+ const bool is_binary = GIMPLE_BINARY_RHS == gclass;
+ const bool is_valid_input = is_ternary || is_binary;
+ gcc_assert(is_valid_input);
+ const_tree rhs = gimple_assign_rhs2(stmt);
+ gcc_assert(rhs);
+ collect_types_from_expr(rhs, types);
+}
+
+static void
+collect_types_from_stmt_assign_rhs1(gimple *stmt, ptrset_t &types)
+{
+ is_gimple_code(stmt, GIMPLE_ASSIGN);
+ const enum gimple_rhs_class gclass = gimple_assign_rhs_class(stmt);
+ const bool is_ternary = GIMPLE_TERNARY_RHS == gclass;
+ const bool is_binary = GIMPLE_BINARY_RHS == gclass;
+ const bool is_unary = GIMPLE_UNARY_RHS == gclass;
+ const bool is_single = GIMPLE_SINGLE_RHS == gclass;
+ const bool is_valid_input = is_ternary || is_binary || is_unary || is_single;
+ gcc_assert(is_valid_input);
+ const_tree rhs = gimple_assign_rhs1(stmt);
+ gcc_assert(rhs);
+ collect_types_from_expr(rhs, types);
+}
+
+static void
+collect_types_from_stmt_assign_rhs(gimple *stmt, ptrset_t &types)
+{
+ is_gimple_code(stmt, GIMPLE_ASSIGN);
+ const enum gimple_rhs_class gclass = gimple_assign_rhs_class(stmt);
+ switch (gclass)
+ {
+ case GIMPLE_TERNARY_RHS:
+ collect_types_from_stmt_assign_rhs3(stmt, types);
+ /* fall-through */
+ case GIMPLE_BINARY_RHS:
+ collect_types_from_stmt_assign_rhs2(stmt, types);
+ /* fall-through */
+ case GIMPLE_UNARY_RHS:
+ case GIMPLE_SINGLE_RHS:
+ collect_types_from_stmt_assign_rhs1(stmt, types);
+ break;
+ default:
+ gcc_unreachable();
+ break;
+ }
+}
+
+static void
+collect_types_from_stmt_assign(gimple *stmt, ptrset_t &types)
+{
+ is_gimple_code(stmt, GIMPLE_ASSIGN);
+ collect_types_from_stmt_assign_lhs(stmt, types);
+ collect_types_from_stmt_assign_rhs(stmt, types);
+}
+
+static void
+collect_types_from_stmt_call_lhs(gimple *stmt, ptrset_t &types)
+{
+ is_gimple_code(stmt, GIMPLE_CALL);
+ const_tree lhs = gimple_call_lhs(stmt);
+ if (!lhs) return;
+ collect_types_from_expr(lhs, types);
+}
+
+static void
+collect_types_from_stmt_call_rhs(gimple *stmt, ptrset_t &types)
+{
+ is_gimple_code(stmt, GIMPLE_CALL);
+ unsigned num_args = gimple_call_num_args(stmt);
+ for (unsigned i = 0; i < num_args; i++)
+ {
+ const_tree arg_i = gimple_call_arg(stmt, i);
+ collect_types_from_expr(arg_i, types);
+ }
+}
+
+static void
+collect_types_from_stmt_call(gimple *stmt, ptrset_t &types)
+{
+ is_gimple_code(stmt, GIMPLE_CALL);
+ collect_types_from_stmt_call_lhs(stmt, types);
+ collect_types_from_stmt_call_rhs(stmt, types);
+}
+
+static void
+collect_types_from_stmt_cond_lhs(gimple *stmt, ptrset_t &types)
+{
+ is_gimple_code(stmt, GIMPLE_COND);
+ const_tree lhs = gimple_cond_lhs(stmt);
+ gcc_assert(lhs);
+ collect_types_from_expr(lhs, types);
+}
+
+static void
+collect_types_from_stmt_cond_rhs(gimple *stmt, ptrset_t &types)
+{
+ is_gimple_code(stmt, GIMPLE_COND);
+ const_tree rhs = gimple_cond_rhs(stmt);
+ gcc_assert(rhs);
+ collect_types_from_expr(rhs, types);
+}
+
+static void
+collect_types_from_stmt_cond(gimple *stmt, ptrset_t &types)
+{
+ is_gimple_code(stmt, GIMPLE_COND);
+ collect_types_from_stmt_cond_lhs(stmt, types);
+ collect_types_from_stmt_cond_rhs(stmt, types);
+}
+
+static void
+collect_types_from_stmt_return(gimple *stmt, ptrset_t &types)
+{
+ is_gimple_code(stmt, GIMPLE_RETURN);
+ const_tree retval = gimple_return_retval(stmt);
+ gcc_assert(retval);
+ collect_types_from_expr(retval, types);
+}
+
+static void
+collect_types_from_stmt(gimple *stmt, ptrset_t &types)
+{
+ gcc_assert(stmt);
+ const enum gimple_code code = gimple_code(stmt);
+ switch (code) {
+ case GIMPLE_ASSIGN:
+ collect_types_from_stmt_assign(stmt, types);
+ break;
+ case GIMPLE_CALL:
+ collect_types_from_stmt_call(stmt, types);
+ break;
+ case GIMPLE_COND:
+ collect_types_from_stmt_cond(stmt, types);
+ break;
+ case GIMPLE_RETURN:
+ collect_types_from_stmt_return(stmt, types);
+ break;
+ case GIMPLE_LABEL:
+ case GIMPLE_PREDICT:
+#ifdef FUZZ_MODE
+ gcc_unreachable();
+#endif
+ break;
+ default:
+ {
+ const char* name = gimple_code_name[code];
+ log("gimple code name %s\n", name);
+ gcc_unreachable();
+ }
+ break;
+ }
+}
+
+static void
+collect_types_from_cnode_decl(cgraph_node *cnode, ptrset_t &types)
+{
+ gcc_assert(cnode);
+ const_tree decl = cnode->decl;
+ gcc_assert(decl);
+ const_tree decl_type = TREE_TYPE(decl);
+ gcc_assert(decl_type);
+ function *func = DECL_STRUCT_FUNCTION (decl);
+ gcc_assert(func);
+ push_cfun(func);
+ // This will collect return, arguments and decl_type itself
+ collect_types(decl_type, types);
+ pop_cfun();
+}
+
+static void
+collect_types_from_cnode_locals(cgraph_node *cnode, ptrset_t &types)
+{
+ gcc_assert(cnode);
+ const_tree decl = cnode->decl;
+ gcc_assert(decl);
+ function *func = DECL_STRUCT_FUNCTION (decl);
+ gcc_assert(func);
+ int i = 0;
+ tree var_decl = NULL;
+ FOR_EACH_LOCAL_DECL(func, i, var_decl)
+ {
+ gcc_assert(var_decl);
+ const_tree var_decl_type = TREE_TYPE(var_decl);
+ collect_types(var_decl_type, types);
+ }
+}
+
+static void
+collect_types_from_cnode_ssa_names(cgraph_node *cnode, ptrset_t &types)
+{
+ gcc_assert(cnode);
+ const_tree decl = cnode->decl;
+ gcc_assert(decl);
+ function *func = DECL_STRUCT_FUNCTION (decl);
+ gcc_assert(func);
+ size_t i = 0;
+ tree ssa_name = NULL;
+ push_cfun(func);
+ FOR_EACH_SSA_NAME(i, ssa_name, cfun)
+ {
+ gcc_assert(ssa_name);
+ const_tree ssa_name_type = TREE_TYPE(ssa_name);
+ collect_types(ssa_name_type, types);
+ }
+ pop_cfun();
+}
+
+static void
+collect_types_from_bb(basic_block bb, ptrset_t &types)
+{
+ gcc_assert(bb);
+ for (auto gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi))
+ {
+ gimple *stmt = gsi_stmt(gsi);
+ gcc_assert(stmt);
+ collect_types_from_stmt(stmt, types);
+ }
+}
+
+static void
+collect_types_from_cnode_bb(cgraph_node *cnode, ptrset_t &types)
+{
+ gcc_assert(cnode);
+ cnode->get_untransformed_body();
+ tree decl = cnode->decl;
+ gcc_assert(decl);
+ function *func = DECL_STRUCT_FUNCTION(decl);
+ gcc_assert(func);
+ basic_block bb = NULL;
+ push_cfun(func);
+ FOR_EACH_BB_FN(bb, func)
+ {
+ gcc_assert(bb);
+ collect_types_from_bb(bb, types);
+ }
+ pop_cfun();
+}
+
+static void
+collect_types_from_global(varpool_node *vnode, ptrset_t &types)
+{
+ gcc_assert(vnode);
+ struct ipa_ref *ref = NULL;
+ for (unsigned i = 0; vnode->iterate_referring(i, ref); i++)
+ {
+ tree decl = vnode->decl;
+ gcc_assert(decl);
+ collect_types_from_var_decl(decl, types);
+ }
+}
+
+static void
+collect_types_from_globals(ptrset_t &types)
+{
+ varpool_node *vnode = NULL;
+ FOR_EACH_VARIABLE (vnode)
+ {
+ collect_types_from_global(vnode, types);
+ }
+}
+
+static void
+collect_types_from_functions_with_gimple_body(cgraph_node *cnode, ptrset_t &types)
+{
+ gcc_assert(cnode);
+ collect_types_from_cnode_decl(cnode, types);
+ collect_types_from_cnode_locals(cnode, types);
+ collect_types_from_cnode_ssa_names(cnode, types);
+ collect_types_from_cnode_bb(cnode, types);
+}
+
+static void
+print_types_in_set(ptrset_t &types)
+{
+ for (auto it = types.points_to_record.cbegin(); it != types.points_to_record.cend(); ++it)
+ {
+ const_tree type = *it;
+ std::string name = type_to_string(type);
+ log("name: %s\n", name.c_str());
+ }
+}
+
+static const bool
+filter_comparisons_functions_char(const char* function_name)
+{
+ // Everything should run
+ if (!flag_tp_comparison_functions) return true;
+
+ const size_t buffer_size = 1024;
+ const size_t cli_length = strlen(flag_tp_comparison_functions);
+ gcc_assert(buffer_size > cli_length);
+ char whitelist[buffer_size];
+ strcpy(whitelist, flag_tp_comparison_functions);
+
+
+ char* saveptr = whitelist;
+ char* token = NULL;
+ while (token = strtok_r(saveptr, ",", &saveptr))
+ {
+ const bool name_allowed = strcmp(token, function_name) == 0;
+ if (name_allowed) return true;
+ }
+
+ return false;
+}
+
+static const bool
+filter_comparisons_functions_int(unsigned function_id)
+{
+ if (!flag_tp_comparison_functions) return true;
+
+ const char* function_name = type_playground::names[function_id];
+ return filter_comparisons_functions_char(function_name);
+}
+
+static const bool
+filter_comparisons_functions(type_playground::type_comparison_func_t func)
+{
+ if (!flag_tp_comparison_functions) return true;
+
+ for (unsigned i = 0; i < type_playground::type_comparisons; i++)
+ {
+ if (func != type_playground::comparisons[i]) continue;
+
+ return filter_comparisons_functions_int(i);
+ }
+
+ return false;
+}
+
+
+static void
+compare_types_in_set(ptrset_t &types)
+{
+ for (auto i = types.points_to_record.cbegin(); i != types.points_to_record.cend(); ++i)
+ {
+ for (auto j = types.points_to_record.cbegin(); j != types.points_to_record.cend(); ++j)
+ {
+ const_tree a = *i;
+ const_tree b = *j;
+ log("%s x %s = ", type_to_string(a).c_str(), type_to_string(b).c_str());
+ for (unsigned k = 0; k < type_playground::type_comparisons; k++)
+ {
+ type_playground::type_comparison_func_t comparison = type_playground::comparisons[k];
+ const bool allowed_to_run = filter_comparisons_functions(comparison);
+ if (!allowed_to_run) continue;
+
+ const bool result = comparison(a, b);
+ log("%s, ", result ? "t" : "f");
+ }
+ log("\n");
+ }
+ }
+}
+
+static void
+filter_out_types_in_set(ptrset_t &types)
+{
+ // compare everything
+ if (!flag_tp_types_compared) return;
+
+ const size_t buffer_size = 1024;
+ const size_t cli_length = strlen(flag_tp_comparison_functions);
+ gcc_assert(buffer_size > cli_length);
+ char whitelist[buffer_size];
+ strcpy(whitelist, flag_tp_types_compared);
+
+ bool name_allowed = false;
+ for (auto it = types.points_to_record.cbegin(); it != types.points_to_record.cend(); name_allowed ? ++it : it = types.points_to_record.erase(it))
+ {
+ const_tree type = *it;
+ std::string observed_name = get_type_identifier(type);
+ char* saveptr = whitelist;
+ char* expected_name = NULL;
+ name_allowed = false;
+
+ while (expected_name = strtok_r(saveptr, ",", &saveptr))
+ {
+ name_allowed |= strcmp(expected_name, observed_name.c_str()) == 0;
+ }
+ }
+
+}
+
+static void
+collect_types(ptrset_t &types)
+{
+ collect_types_from_globals(types);
+
+ cgraph_node *node = NULL;
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node)
+ {
+ node->get_untransformed_body();
+ collect_types_from_functions_with_gimple_body(node, types);
+ // We still need to collect types from
+ // the function signatures of functions without gimple bodies...
+ }
+}
+
+static unsigned int
+iphw_execute()
+{
+ //test_type_equality::run_tests();
+ //test_naming_types::run_tests();
+ ptrset_t types;
+
+ collect_types(types);
+ filter_out_types_in_set(types);
+ compare_types_in_set(types);
+ return 0;
+}
+
+namespace {
+const pass_data pass_data_ipa_escape_analysis =
+{
+ SIMPLE_IPA_PASS,
+ "escape-analysis",
+ OPTGROUP_NONE,
+ TV_NONE,
+ (PROP_cfg | PROP_ssa),
+ 0,
+ 0,
+ TODO_rebuild_alias,
+ 0,
+};
+
+class pass_ipa_escape_analysis : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_escape_analysis (gcc::context *ctx)
+ : simple_ipa_opt_pass(pass_data_ipa_escape_analysis, ctx)
+ {}
+
+ virtual bool gate(function*) { return flag_ipa_escape_analysis; }
+ virtual unsigned execute (function*) { return iphw_execute(); }
+};
+} // anon namespace
+
+simple_ipa_opt_pass*
+make_pass_ipa_escape_analysis (gcc::context *ctx)
+{
+ return new pass_ipa_escape_analysis (ctx);
+}
diff --git a/gcc/name-types.c b/gcc/name-types.c
new file mode 100644
index 00000000000..800ba6cb1d2
--- /dev/null
+++ b/gcc/name-types.c
@@ -0,0 +1,420 @@
+#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 "types-inlines.h"
+#include <set>
+#include <string>
+
+#include "name-types.h"
+
+// Using std::string because it will manage memory for us
+// And we don't know whether the user will free the memory.
+// Also that's why we are returning a value rather than a
+// pointer...
+
+static const std::string
+type_to_string_simple(const_tree type)
+{
+ gcc_assert(type);
+ const enum tree_code code = TREE_CODE(type);
+ bool valid_input = false;
+ 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:
+ valid_input = true;
+ break;
+ default:
+ valid_input = false;
+ break;
+ }
+ gcc_assert(valid_input);
+
+
+ return std::string(get_tree_code_name(code));
+}
+
+static const std::string
+type_to_string_get_field_name(const_tree field)
+{
+ assert_is_type(field, FIELD_DECL);
+ const_tree decl_name = DECL_NAME(field);
+ if (!decl_name) return std::string("");
+
+ const char* identifier = IDENTIFIER_POINTER(decl_name);
+ return std::string(identifier);
+}
+
+static const unsigned
+type_to_string_get_field_offset(const_tree field)
+{
+ assert_is_type(field, FIELD_DECL);
+ tree cst = byte_position(field);
+ gcc_assert(cst);
+ unsigned offset = tree_to_uhwi (cst);
+ return offset;
+}
+
+static const unsigned
+type_to_string_get_type_size(const_tree type)
+{
+ gcc_assert(type);
+ const_tree type_size = TYPE_SIZE(type);
+ const bool is_incomplete = NULL_TREE == type_size;
+ if (is_incomplete) return 0;
+
+ const bool fits_uhwi = tree_fits_uhwi_p(type_size);
+ if (fits_uhwi) return tree_to_uhwi (type_size);
+
+ const bool fits_shwi = tree_fits_shwi_p(type_size);
+ if (fits_shwi) return tree_to_shwi (type_size);
+
+ return 0;
+}
+
+const std::string
+get_type_identifier(const_tree type)
+{
+ tree name = TYPE_NAME(type);
+ // The TYPE_NAME will be NULL_TREE for a type
+ // that is not a built-in type, the result of a typedef
+ // or a named class type.
+ const bool no_name = NULL_TREE == name;
+ if (no_name) return std::string("");
+
+ const enum tree_code name_code = TREE_CODE(name);
+ const bool is_name_type_decl = TYPE_DECL == name_code;
+ name = is_name_type_decl ? DECL_NAME(name) : name;
+ const char* identifier_ptr = IDENTIFIER_POINTER(name);
+ gcc_assert(identifier_ptr);
+ return std::string(identifier_ptr);
+}
+
+static const std::string
+type_to_string_get_record_name(const_tree type)
+{
+ assert_is_type(type, RECORD_TYPE);
+ tree name = TYPE_NAME(type);
+ // The TYPE_NAME will be NULL_TREE for a type
+ // that is not a built-in type, the result of a typedef
+ // or a named class type.
+ const bool no_name = NULL_TREE == name;
+ if (no_name) return std::string("");
+
+ const enum tree_code name_code = TREE_CODE(name);
+ const bool is_name_type_decl = TYPE_DECL == name_code;
+ name = is_name_type_decl ? DECL_NAME(name) : name;
+ const char* identifier_ptr = IDENTIFIER_POINTER(name);
+ gcc_assert(identifier_ptr);
+ return std::string(identifier_ptr);
+}
+
+static const std::string
+type_to_string_get_record_or_union_name(const_tree type)
+{
+ const enum tree_code code = TREE_CODE(type);
+ const bool is_record = RECORD_TYPE == code;
+ const bool is_union = UNION_TYPE == code;
+ const bool is_valid_input = is_record || is_union;
+ gcc_assert(is_valid_input);
+ tree name = TYPE_NAME(type);
+
+ // The TYPE_NAME will be NULL_TREE for a type
+ // that is not a built-in type, the result of a typedef
+ // or a named class type.
+ const bool no_name = NULL_TREE == name;
+ if (no_name) return std::string("");
+
+ const enum tree_code name_code = TREE_CODE(name);
+ const bool is_name_type_decl = TYPE_DECL == name_code;
+ name = is_name_type_decl ? DECL_NAME(name) : name;
+ const char* identifier_ptr = IDENTIFIER_POINTER(name);
+ gcc_assert(identifier_ptr);
+ return std::string(identifier_ptr);
+}
+
+/*
+ * The idea behind this function is to receive either
+ * a record or a union type and return a string that
+ * represents this type.
+ * The output should look something like this:
+ * 0: astruct {
+ * 0: int a
+ * 8: int b
+ * 16: bstruct*
+ * 24: cstruct {
+ * 0: int a
+ * }
+ * 32: {
+ * }
+ * }
+ * The question I have now... is... should we follos bstruct*
+ * to see what it points to? Because, maybe there's two bstruct*s
+ * defined in different TU?
+ * So maybe more like this:
+ * 0: astruct {
+ * 0: int a
+ * 8: int b
+ * 16: bstruct {
+ * 0: int a
+ * }*
+ * 24: cstruct {
+ * 0: int a
+ * }
+ * 32: {
+ * }
+ */
+static const std::string
+type_to_string_record_or_union(const_tree type)
+{
+ gcc_assert(type);
+ const enum tree_code code = TREE_CODE(type);
+ const bool is_record = RECORD_TYPE == code;
+ const bool is_union = UNION_TYPE == code;
+ const bool is_valid_input = is_record || is_union;
+ gcc_assert(is_valid_input);
+
+ std::string name = type_to_string_get_record_or_union_name(type);
+ std::string aggregate = name + std::string(" {");
+
+ for (tree field = TYPE_FIELDS(type); field; field = DECL_CHAIN(field))
+ {
+ std::string field_name = type_to_string_get_field_name(field);
+ const_tree field_type = TREE_TYPE(field);
+ const unsigned field_offset = type_to_string_get_field_offset(field);
+ std::string field_type_name = type_to_string(field_type, field_offset);
+ aggregate += field_type_name + std::string(";");
+ }
+
+ aggregate += "}";
+ return aggregate;
+}
+
+static const std::string
+type_to_string_record(const_tree type)
+{
+ assert_is_type(type, RECORD_TYPE);
+ return type_to_string_record_or_union(type);
+}
+
+static const std::string
+type_to_string_union(const_tree type)
+{
+ assert_is_type(type, UNION_TYPE);
+ return type_to_string_record_or_union(type);
+}
+
+static const std::string
+type_to_string_wrapper(const_tree type)
+{
+ gcc_assert(type);
+ const enum tree_code code = TREE_CODE(type);
+ bool is_valid_input = false;
+ switch (code)
+ {
+ case POINTER_TYPE:
+ case ARRAY_TYPE:
+ case REFERENCE_TYPE:
+ is_valid_input = true;
+ break;
+ default:
+ is_valid_input = false;
+ break;
+ }
+ gcc_assert(is_valid_input);
+
+ const_tree inner_type = TREE_TYPE(type);
+ return type_to_string(inner_type, 0, false);
+}
+
+static const std::string
+type_to_string_pointer(const_tree type)
+{
+ assert_is_type(type, POINTER_TYPE);
+ return type_to_string_wrapper(type) + std::string("*");
+}
+
+static const std::string
+type_to_string_array(const_tree type)
+{
+ assert_is_type(type, ARRAY_TYPE);
+ return type_to_string_wrapper(type) + std::string("[]");
+}
+
+static const std::string
+type_to_string_reference(const_tree type)
+{
+ assert_is_type(type, REFERENCE_TYPE);
+ return type_to_string_wrapper(type) + std::string("&");
+}
+
+static const std::string
+type_to_string_function_or_method(const_tree type)
+{
+ 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 = is_function || is_method;
+ gcc_assert(is_valid);
+
+ const_tree return_type = TREE_TYPE(type);
+ gcc_assert(return_type);
+
+ const std::string return_type_name = type_to_string(return_type, 0, false);
+
+ std::string aggregate("");
+
+ for(tree param = TYPE_ARG_TYPES(type); param; param = TREE_CHAIN(param))
+ {
+ const_tree param_type = TREE_VALUE(param);
+ //TODO: Why no param type?
+ //gcc_assert(param_type);
+ const bool has_more_params = TREE_CHAIN(param);
+ aggregate += type_to_string(param_type);
+ if (!has_more_params) break;
+
+ aggregate += std::string(", ");
+ }
+
+ //TODO: Add base_type for method types
+ std::string retval = return_type_name + std::string("(") + aggregate + std::string(")");
+ return retval;
+}
+
+static const std::string
+type_to_string_function(const_tree type)
+{
+ assert_is_type(type, FUNCTION_TYPE);
+ return type_to_string_function_or_method(type);
+}
+
+static const std::string
+type_to_string_method(const_tree type)
+{
+ assert_is_type(type, METHOD_TYPE);
+ return type_to_string_function_or_method(type);
+}
+
+
+const std::string
+type_to_string(const_tree type, const unsigned field_offset, const bool add_prelude)
+{
+ if (!type) return std::string("why");
+ gcc_assert(type);
+ const enum tree_code code = TREE_CODE(type);
+ const unsigned size = type_to_string_get_type_size(type);
+ std::string prelude = add_prelude ? std::to_string(field_offset) + std::string(",") + std::to_string(field_offset + size) + std::string(":") : std::string("");
+
+ 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:
+ return prelude + type_to_string_simple(type);
+ break;
+ default:
+ break;
+ }
+
+ switch (code)
+ {
+ case RECORD_TYPE:
+ return prelude + type_to_string_record(type);
+ break;
+ case UNION_TYPE:
+ return prelude + type_to_string_union(type);
+ break;
+ case POINTER_TYPE:
+ return prelude + type_to_string_pointer(type);
+ break;
+ case REFERENCE_TYPE:
+ return prelude + type_to_string_reference(type);
+ break;
+ case ARRAY_TYPE:
+ return prelude + type_to_string_array(type);
+ break;
+ case FUNCTION_TYPE:
+ return prelude + type_to_string_function(type);
+ break;
+ case METHOD_TYPE:
+ return prelude + type_to_string_method(type);
+ break;
+ case QUAL_UNION_TYPE:
+ case LANG_TYPE:
+ default:
+ // unimplemented
+ gcc_unreachable();
+ break;
+ }
+
+ gcc_unreachable();
+ return std::string("you shouldn't ever see this");
+}
+
+namespace test_naming_types {
+
+void test_generic_to_string(const enum tree_code code, const char * expected_char_array)
+{
+ std::string expected_value(expected_char_array);
+ tree type = make_node(code);
+ std::string observed_value = type_to_string(type);
+ const bool success = expected_value.compare(observed_value) == 0;
+ gcc_assert(success);
+
+}
+void test_simple_to_string()
+{
+ test_generic_to_string(VOID_TYPE, "0:void_type");
+ test_generic_to_string(INTEGER_TYPE, "0:integer_type");
+ test_generic_to_string(REAL_TYPE, "0:real_type");
+ test_generic_to_string(FIXED_POINT_TYPE, "0:fixed_point_type");
+ test_generic_to_string(COMPLEX_TYPE, "0:complex_type");
+ test_generic_to_string(ENUMERAL_TYPE, "0:enumeral_type");
+ test_generic_to_string(BOOLEAN_TYPE, "0:boolean_type");
+ test_generic_to_string(OFFSET_TYPE, "0:offset_type");
+}
+
+void run_tests()
+{
+ test_simple_to_string();
+}
+};
diff --git a/gcc/name-types.h b/gcc/name-types.h
new file mode 100644
index 00000000000..538956fdd5d
--- /dev/null
+++ b/gcc/name-types.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "tree.h"
+#include <string>
+
+const std::string type_to_string(const_tree type, const unsigned field_offset=0, const bool add_prelude=true);
+const std::string get_type_identifier(const_tree type);
+
+namespace test_naming_types {
+void run_tests();
+};
diff --git a/gcc/passes.def b/gcc/passes.def
index 8a54178a7e0..e0d2711c432 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -151,6 +151,7 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_ipa_devirt);
NEXT_PASS (pass_ipa_type_escape_analysis);
NEXT_PASS (pass_ipa_hello_world);
+ NEXT_PASS (pass_ipa_escape_analysis);
NEXT_PASS (pass_ipa_cp);
NEXT_PASS (pass_ipa_sra);
NEXT_PASS (pass_ipa_cdtor_merge);
diff --git a/gcc/testsuite/gcc.dg/ipa/type-playground-00.c b/gcc/testsuite/gcc.dg/ipa/type-playground-00.c
new file mode 100644
index 00000000000..6bddfac9939
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/type-playground-00.c
@@ -0,0 +1,21 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-escape-analysis -fdump-ipa-escape-analysis -ftp-comparison-functions=EQ_POINTER -ftp-types-compared=int " } */
+
+int
+main ()
+{
+ int a = 0;
+ const int b = 0;
+ return 0;
+}
+
+// This is proof that comparing trees using only
+// pointer equality yields different trees
+// when types have different attributes.
+// i.e.
+// TREE_TYPE(a) == TREE_TYPE(b)
+// evaluates to false
+
+
+/* { dg-final { scan-wpa-ipa-dump "0,32:integer_type x 0,32:integer_type = t," "escape-analysis" } } */
+
diff --git a/gcc/testsuite/gcc.dg/ipa/type-playground-01.c b/gcc/testsuite/gcc.dg/ipa/type-playground-01.c
new file mode 100644
index 00000000000..f85ecc13ef1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/type-playground-01.c
@@ -0,0 +1,19 @@
+/* { dg-do run } */
+/* { dg-options "-flto -fipa-escape-analysis -fdump-ipa-escape-analysis -ftp-comparison-functions=EQ_STRUCTURAL -ftp-types-compared=astruct_s" } */
+
+struct astruct_s {
+ struct astruct_s* a;
+};
+
+int
+main(int argc, char* argv)
+{
+ struct astruct_s a;
+}
+
+// This is proof that an incomplete type cannot be compared
+// via structural equality.
+
+// 0,64:astruct_s {0,64:astruct_s {}*;} x 0,0:astruct_s {} = f,
+// I am not an expert on regex
+/* { dg-final { scan-wpa-ipa-dump "0,64:astruct_s .0,64:astruct_s ..... x 0,0:astruct_s .. = f," "escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/type-playground-02.c b/gcc/testsuite/gcc.dg/ipa/type-playground-02.c
new file mode 100644
index 00000000000..128dc8f3b82
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/type-playground-02.c
@@ -0,0 +1,19 @@
+/* { dg-do run } */
+/* { dg-options "-flto -fipa-escape-analysis -fdump-ipa-escape-analysis -ftp-comparison-functions=EQ_MAIN_VARIANT -ftp-types-compared=astruct_s" } */
+
+struct astruct_s {
+ struct astruct_s* a;
+};
+
+int
+main(int argc, char* argv)
+{
+ struct astruct_s a;
+}
+
+// This is proof that an incomplete type cannot be compared
+// via main variant equality.
+
+// 0,64:astruct_s {0,64:astruct_s {}*;} x 0,0:astruct_s {} = f,
+// I am not an expert on regex
+/* { dg-final { scan-wpa-ipa-dump "0,64:astruct_s .0,64:astruct_s ..... x 0,0:astruct_s .. = f," "escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/type-playground-03.c b/gcc/testsuite/gcc.dg/ipa/type-playground-03.c
new file mode 100644
index 00000000000..4ffe949f826
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/type-playground-03.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options "-flto -fipa-escape-analysis -fdump-ipa-escape-analysis -ftp-comparison-functions=EQ_IDENTIFIER -ftp-types-compared=astruct_s" } */
+
+struct astruct_s {
+ struct astruct_s* a;
+};
+
+int
+main(int argc, char* argv)
+{
+ struct astruct_s a;
+}
+
+// This is proof that an incomplete type **CAN** be compared
+// via identifier identity.
+// Intuitevely, identifier identity may give false positives (and maybe false negatives too?)
+// So, it must be the last resort comparisons.
+//
+// If we say that an identifier comparison may give false positives and false negatives
+// then maybe it would be useful to documents attempts to explicitly produce false positives
+// and false negatives to better understand what causes them.
+
+// 0,64:astruct_s {0,64:astruct_s {}*;} x 0,0:astruct_s {} = t,
+// I am not an expert on regex
+/* { dg-final { scan-wpa-ipa-dump "0,64:astruct_s .0,64:astruct_s ..... x 0,0:astruct_s .. = t," "escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/type-playground-04.c b/gcc/testsuite/gcc.dg/ipa/type-playground-04.c
new file mode 100644
index 00000000000..7b490f6eca3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/type-playground-04.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options "-flto -fipa-escape-analysis -fdump-ipa-escape-analysis -ftp-comparison-functions=EQ_CANONICAL -ftp-types-compared=astruct_s" } */
+
+struct astruct_s {
+ struct astruct_s* a;
+};
+
+int
+main(int argc, char* argv)
+{
+ struct astruct_s a;
+}
+
+// This is proof that an incomplete type **CAN** be compared
+// via identifier identity.
+// Intuitevely, identifier identity may give false positives (and maybe false negatives too?)
+// So, it must be the last resort comparisons.
+//
+// If we say that an identifier comparison may give false positives and false negatives
+// then maybe it would be useful to documents attempts to explicitly produce false positives
+// and false negatives to better understand what causes them.
+
+// 0,64:astruct_s {0,64:astruct_s {}*;} x 0,0:astruct_s {} = f,
+// I am not an expert on regex
+/* { dg-final { scan-wpa-ipa-dump "0,64:astruct_s .0,64:astruct_s ..... x 0,0:astruct_s .. = f," "escape-analysis" } } */
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 0c14a827a2e..a9a9c96a4dc 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -503,6 +503,7 @@ extern simple_ipa_opt_pass *make_pass_ipa_free_lang_data (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_free_fn_summary (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_type_escape_analysis (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_hello_world (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_escape_analysis (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_cp (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_sra (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_icf (gcc::context *ctxt);
diff --git a/gcc/types-inlines.h b/gcc/types-inlines.h
new file mode 100644
index 00000000000..340108fcf8f
--- /dev/null
+++ b/gcc/types-inlines.h
@@ -0,0 +1,37 @@
+#pragma once
+
+
+inline void
+log(const char* const fmt, ...)
+{
+ if (!dump_file) return;
+
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(dump_file, fmt, args);
+ va_end(args);
+}
+
+inline void
+assert_is_complete(const_tree a)
+{
+ gcc_assert(a);
+ const_tree type_size = TYPE_SIZE(a);
+ gcc_assert(NULL_TREE != type_size);
+}
+
+inline void
+assert_is_type(const_tree a, const enum tree_code expected_code)
+{
+ gcc_assert(a);
+ const enum tree_code observed_code = TREE_CODE(a);
+ const bool eq_codes = observed_code == expected_code;
+ gcc_assert(eq_codes);
+}
+
+inline void
+assert_is_complete_type(const_tree a, const enum tree_code expected_code)
+{
+ //assert_is_complete(a);
+ assert_is_type(a, expected_code);
+}