summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErick Ochoa <erick.ochoa@theobroma-systems.com>2020-05-11 13:28:35 +0200
committerErick Ochoa <erick.ochoa@theobroma-systems.com>2020-06-03 16:05:54 +0200
commitc9232b5b48d6c6264d59d6bf8c46b9b8c5d09947 (patch)
tree83a76436fa11ac6cef814df8c0d1244f6796ea89
parent4ab6bc2b779267efb735d249764843ec7f4f9edd (diff)
Adds passes to print type names
-rw-r--r--gcc/Makefile.in1
-rw-r--r--gcc/collect-types.c10
-rw-r--r--gcc/ipa-hello-world.c40
-rw-r--r--gcc/name-types.c388
-rw-r--r--gcc/name-types.h10
-rw-r--r--gcc/passes.def2
-rw-r--r--gcc/types-inlines.h10
7 files changed, 442 insertions, 19 deletions
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 45c9d8a0f2c..e9fb0ac228c 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1410,6 +1410,7 @@ OBJS = \
ipa-hello-world.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
index 18c4ab3ca92..20a5ad4eeba 100644
--- a/gcc/collect-types.c
+++ b/gcc/collect-types.c
@@ -109,11 +109,12 @@ collect_types_from_function_or_method_type(const_tree type, typeset &types)
gcc_assert(ret_type);
collect_types(ret_type, types);
- for (tree param = TYPE_ARG_TYPES(type); param; param = TREE_CHAIN(param))
+ tree arg_node = TYPE_ARG_TYPES(type);
+ while (NULL_TREE != arg_node)
{
- const_tree param_type = TREE_TYPE(param);
- gcc_assert(param_type);
- collect_types(param_type, types);
+ tree arg_node_type = TREE_VALUE(arg_node);
+ collect_types(arg_node_type, types);
+ arg_node = TREE_CHAIN(arg_node);
}
}
@@ -184,6 +185,7 @@ collect_types(const_tree type, typeset &types)
case QUAL_UNION_TYPE:
case LANG_TYPE:
default:
+ //log("%s\n", get_tree_code_name(code));
gcc_unreachable();
break;
}
diff --git a/gcc/ipa-hello-world.c b/gcc/ipa-hello-world.c
index 09cf4526780..72294961af6 100644
--- a/gcc/ipa-hello-world.c
+++ b/gcc/ipa-hello-world.c
@@ -31,10 +31,23 @@
#include "compare-types.h"
#include "types-inlines.h"
#include <set>
+#include <string>
#include "collect-types.h"
+#include "name-types.h"
+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);
+}
+
static void
collect_types_from_cnode_decl(cgraph_node *cnode, typeset &types)
{
@@ -43,8 +56,12 @@ collect_types_from_cnode_decl(cgraph_node *cnode, typeset &types)
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
@@ -72,9 +89,10 @@ collect_types_from_cnode_ssa_names(cgraph_node *cnode, typeset &types)
const_tree decl = cnode->decl;
gcc_assert(decl);
function *func = DECL_STRUCT_FUNCTION (decl);
- push_cfun(func);
+ 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);
@@ -90,13 +108,25 @@ collect_types_from_functions_with_gimple_body(cgraph_node *cnode, typeset &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_ssa_names(cnode, types);
+}
+
+static void
+print_types_in_set(typeset &types)
+{
+ for (auto it = types.cbegin(); it != types.cend(); ++it)
+ {
+ const_tree type = *it;
+ std::string name = type_to_string(type);
+ log("name: %s\n", name.c_str());
+ }
}
static unsigned int
iphw_execute()
{
- test_type_equality::run_tests();
+ //test_type_equality::run_tests();
+ //test_naming_types::run_tests();
cgraph_node *node = NULL;
typeset types;
FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node)
@@ -104,6 +134,8 @@ iphw_execute()
node->get_untransformed_body();
collect_types_from_functions_with_gimple_body(node, types);
}
+
+ print_types_in_set(types);
return 0;
}
@@ -128,7 +160,7 @@ public:
: simple_ipa_opt_pass(pass_data_ipa_hello_world, ctx)
{}
- virtual bool gate(function*) { return false; }
+ virtual bool gate(function*) { return flag_ipa_hello_world; }
virtual unsigned execute (function*) { return iphw_execute(); }
};
} // anon namespace
diff --git a/gcc/name-types.c b/gcc/name-types.c
new file mode 100644
index 00000000000..fb490d0c8f4
--- /dev/null
+++ b/gcc/name-types.c
@@ -0,0 +1,388 @@
+#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(field);
+ 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;
+
+}
+
+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)
+{
+ //TODO: FIXME
+ //I think it should also work for UNIONS, but I should then rewrite the function
+ //to avoid the assertion
+ return type_to_string_get_record_name(type);
+}
+
+/*
+ * 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..a56b459b87f
--- /dev/null
+++ b/gcc/name-types.h
@@ -0,0 +1,10 @@
+#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);
+
+namespace test_naming_types {
+void run_tests();
+};
diff --git a/gcc/passes.def b/gcc/passes.def
index 442e1e7b0e1..98195c02f66 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -149,7 +149,6 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_ipa_profile);
NEXT_PASS (pass_ipa_icf);
NEXT_PASS (pass_ipa_devirt);
- NEXT_PASS (pass_ipa_hello_world);
NEXT_PASS (pass_ipa_cp);
NEXT_PASS (pass_ipa_sra);
NEXT_PASS (pass_ipa_cdtor_merge);
@@ -172,6 +171,7 @@ along with GCC; see the file COPYING3. If not see
compiled unit. */
INSERT_PASSES_AFTER (all_late_ipa_passes)
NEXT_PASS (pass_materialize_all_clones);
+ NEXT_PASS (pass_ipa_hello_world);
NEXT_PASS (pass_ipa_pta);
NEXT_PASS (pass_omp_simd_clone);
TERMINATE_PASS_LIST (all_late_ipa_passes)
diff --git a/gcc/types-inlines.h b/gcc/types-inlines.h
index 9d91bc050d2..24bd23dddc9 100644
--- a/gcc/types-inlines.h
+++ b/gcc/types-inlines.h
@@ -9,13 +9,3 @@ assert_is_type(const_tree a, const enum tree_code expected_code)
gcc_assert(eq_codes);
}
-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);
-}