#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" #include "type-walker.hpp" // 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) { 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(); } };