From c9232b5b48d6c6264d59d6bf8c46b9b8c5d09947 Mon Sep 17 00:00:00 2001 From: Erick Ochoa Date: Mon, 11 May 2020 13:28:35 +0200 Subject: Adds passes to print type names --- gcc/Makefile.in | 1 + gcc/collect-types.c | 10 +- gcc/ipa-hello-world.c | 40 +++++- gcc/name-types.c | 388 ++++++++++++++++++++++++++++++++++++++++++++++++++ gcc/name-types.h | 10 ++ gcc/passes.def | 2 +- gcc/types-inlines.h | 10 -- 7 files changed, 442 insertions(+), 19 deletions(-) create mode 100644 gcc/name-types.c create mode 100644 gcc/name-types.h 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 +#include #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 +#include + +#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 + +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); -} -- cgit v1.2.3