diff options
Diffstat (limited to 'gcc/name-types.c')
-rw-r--r-- | gcc/name-types.c | 420 |
1 files changed, 420 insertions, 0 deletions
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(); +} +}; |