diff options
author | Erick Ochoa <erick.ochoa@theobroma-systems.com> | 2020-06-08 15:23:31 +0200 |
---|---|---|
committer | Erick Ochoa <erick.ochoa@theobroma-systems.com> | 2020-06-08 15:23:31 +0200 |
commit | e17befe197116a35e07f8e466a199569491ac861 (patch) | |
tree | ae0e9cf31bd383c8596fc9ace4f9b72b022ecef9 | |
parent | 140efef10e83422f31b8773dd0ffbf72d2fb0741 (diff) |
Deletes and comments previous API
-rw-r--r-- | gcc/Makefile.in | 2 | ||||
-rw-r--r-- | gcc/common.opt | 8 | ||||
-rw-r--r-- | gcc/ipa-hello-world.c | 569 | ||||
-rw-r--r-- | gcc/ipa-hello-world.h | 18 | ||||
-rw-r--r-- | gcc/ipa-str-reorg-dead-field-eliminate.c | 19 | ||||
-rw-r--r-- | gcc/ipa-type-escape-analysis.c | 962 | ||||
-rw-r--r-- | gcc/ipa-type-escape-analysis.h | 21 | ||||
-rw-r--r-- | gcc/passes.def | 2 | ||||
-rw-r--r-- | gcc/tree-pass.h | 2 |
9 files changed, 8 insertions, 1595 deletions
diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 74afacd6128..75f1086c74b 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1407,8 +1407,6 @@ OBJS = \ incpath.o \ init-regs.o \ internal-fn.o \ - ipa-type-escape-analysis.o \ - ipa-hello-world.o \ ipa-prototype.o \ type-walker.o \ expr-walker.o \ diff --git a/gcc/common.opt b/gcc/common.opt index 7313513d08a..19b0b255bdc 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -3444,14 +3444,6 @@ fipa-typelist-field= Common Joined Report Var(flag_ipa_typelist_field) Init(0) -fipa-typelist-field=<string> Name of struct of interest -fipa-type-escape-analysis -Common Report Var(flag_ipa_type_escape_analysis) Optimization -Type escape analysis - -fipa-hello-world -Common Report Var(flag_ipa_hello_world) Optimization -Hello world - ftp-types-compared= Common Joined Report Var(flag_tp_types_compared) Init(0) diff --git a/gcc/ipa-hello-world.c b/gcc/ipa-hello-world.c deleted file mode 100644 index 20c122f3a16..00000000000 --- a/gcc/ipa-hello-world.c +++ /dev/null @@ -1,569 +0,0 @@ -#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-cfg.h" -#include "gimple.h" -#include "cfg.h" // needed for gimple-iterator.h -#include "gimple-iterator.h" - -#include <map> -#include <set> - -#include "ipa-type-escape-analysis.h" -#include "ipa-str-reorg-utils.h" -#include "ipa-hello-world.h" - - -//TODO: place in header file -inline static void -print_function (cgraph_node *cnode) -{ - if (!dump_file) - return; - gcc_assert (cnode); - cnode->get_untransformed_body (); - dump_function_to_file (cnode->decl, dump_file, TDF_NONE); -} - -//TODO: do not use pair. -//This names are unintelligible -typedef std::pair<unsigned /* reads */, unsigned /* writes */> accesses; -struct field_comparator -{ - bool operator()(const fields &left, const fields &right) const - { - const_tree left_record = left.first; - gcc_assert(left_record); - const_tree right_record = right.first; - gcc_assert(right_record); - // Make sure that we are only comparing valid types... - const enum tree_code tree_code_left_record = TREE_CODE(left_record); - const enum tree_code tree_code_right_record = TREE_CODE(right_record); - const bool is_left_record_type = RECORD_TYPE == tree_code_left_record; - const bool is_right_record_type = RECORD_TYPE == tree_code_right_record; - gcc_assert(is_left_record_type); - gcc_assert(is_right_record_type); - const bool are_left_and_right_valid = is_left_record_type && is_right_record_type; - gcc_assert(are_left_and_right_valid); - - // Handle typedefs: - // Get the main variants of the main types - const_tree main_variant_left = TYPE_MAIN_VARIANT(left_record); - gcc_assert(main_variant_left); - const_tree main_variant_right = TYPE_MAIN_VARIANT(right_record); - gcc_assert(main_variant_right); - // If they are not equal, we can do a comparison of the types here... - const bool are_main_variants_equal = main_variant_left == main_variant_right; - const bool left_type_less_than_right_type = main_variant_left < main_variant_right; - if (!are_main_variants_equal) return left_type_less_than_right_type; - - // If they are equal, that means that we are comparing fields defined in the same record - const_tree left_field = left.second; - gcc_assert(left_field); - const_tree right_field = right.second; - gcc_assert(right_field); - // Make sure that they are valid - const enum tree_code tree_code_left_field = TREE_CODE(left_field); - const enum tree_code tree_code_right_field = TREE_CODE(right_field); - const bool is_left_field_field_decl = FIELD_DECL == tree_code_left_field; - const bool is_right_field_field_decl = FIELD_DECL == tree_code_right_field; - const bool are_left_and_right_field_decls = is_left_field_field_decl && is_right_field_field_decl; - gcc_assert(are_left_and_right_field_decls); - - // Compare on the field offset. - const_tree left_constant = byte_position(left_field); - gcc_assert(left_constant); - const_tree right_constant = byte_position(right_field); - gcc_assert(right_constant); - unsigned left_offset = tree_to_uhwi(left_constant); - unsigned right_offset = tree_to_uhwi(right_constant); - const bool left_offset_less_than_right_offset = left_offset < right_offset; - return left_offset_less_than_right_offset; - } -}; - -typedef std::map<fields, accesses, field_comparator> field_access_counter; -typedef std::set<const_tree> record_set; - -enum access_code { READ_ACCESS, WRITE_ACCESS }; - -void count_access_for_types_in_expr(const_tree expr, const record_set &non_escaping_records, field_access_counter &counter, const enum access_code access); - -void -count_access_for_type_in_component_ref(const_tree component_ref, const record_set &non_escaping_records, field_access_counter &counter, const enum access_code access) -{ - log("types in component_ref\n"); - gcc_assert(component_ref); - enum tree_code tree_code_component_ref = TREE_CODE(component_ref); - const bool is_component_ref = COMPONENT_REF == tree_code_component_ref; - gcc_assert(is_component_ref); - - const_tree _struct = TREE_OPERAND(component_ref, 0); - gcc_assert(_struct); - - log ("going in recursion\n"); - count_access_for_types_in_expr(_struct, non_escaping_records, counter, READ_ACCESS); - const_tree tree_type_struct = TREE_TYPE(_struct); - gcc_assert(tree_type_struct); - enum tree_code tree_type_struct_code = TREE_CODE(tree_type_struct); - const bool is_record_type = RECORD_TYPE == tree_type_struct_code; - //TODO: Also write something for UNION_TYPE - switch (tree_type_struct_code) - { - case UNION_TYPE: return; break; - case RECORD_TYPE: break; - default: gcc_unreachable(); break; - } - gcc_assert(is_record_type); - - //FIXME: Future proofing or making things more difficult to read? - bool in_set = -#if __cplusplus > 201703L - non_escaping_records.contains(tree_type_struct) -#else - non_escaping_records.find(tree_type_struct) != non_escaping_records.end() -#endif - ; - - in_set |= -#if __cplusplus > 201703L - non_escaping_records.contains(TYPE_MAIN_VARIANT(tree_type_struct)) -#else - non_escaping_records.find(TYPE_MAIN_VARIANT(tree_type_struct)) != non_escaping_records.end() -#endif - ; - - - log("%s is in non_escaping_records ? %s\n", get_type_name(tree_type_struct), in_set ? "true" : "false"); - log("access is %s\n", access == READ_ACCESS ? "read_access" : "write_access"); - log("%s is escaping %s\n", get_type_name(tree_type_struct), in_set ? "true" : "false"); - if (!in_set) return; - - const_tree field = TREE_OPERAND(component_ref, 1); - gcc_assert(field); - enum tree_code tree_code_field = TREE_CODE(field); - const bool is_field_decl = FIELD_DECL == tree_code_field; - gcc_assert(is_field_decl); - - const std::pair<const_tree, const_tree> struct_field_pair = std::make_pair(tree_type_struct, field); - accesses &access_counter = counter[struct_field_pair]; - - switch (access) - { - case READ_ACCESS: - //TODO: do not use pair. - //This names are unintelligible - access_counter.first++; - log("%s.%s read %d\n", get_type_name(tree_type_struct), get_field_name(field), access_counter.first); - break; - case WRITE_ACCESS: - //TODO: do not use pair. - //This names are unintelligible - access_counter.second++; - log("%s.%s write %d\n", get_type_name(tree_type_struct), get_field_name(field), access_counter.second); - break; - default: - gcc_unreachable(); - break; - } -} - -static inline void -is_addr_expr_p(const_tree expr) -{ - gcc_assert(expr); - const enum tree_code code = TREE_CODE(expr); - const bool is_addr_expr = ADDR_EXPR == code; - gcc_assert(is_addr_expr); -} - - -void -count_access_for_type_in_addr_expr(const_tree expr, const record_set &non_escaping_records, field_access_counter &counter, const enum access_code access) -{ - is_addr_expr_p(expr); - const_tree op0 = TREE_OPERAND(expr, 0); - count_access_for_types_in_expr(op0, non_escaping_records, counter, access); -} - -static inline void -is_array_expr_p(const_tree expr) -{ - gcc_assert(expr); - const enum tree_code code = TREE_CODE(expr); - const bool is_addr_expr = ARRAY_REF == code; - gcc_assert(is_addr_expr); -} - -void -count_access_for_type_in_array_expr(const_tree expr, const record_set &non_escaping_records, field_access_counter &counter, const enum access_code access) -{ - is_array_expr_p(expr); - const_tree op0 = TREE_OPERAND(expr, 0); - const_tree op1 = TREE_OPERAND(expr, 1); - count_access_for_types_in_expr(op0, non_escaping_records, counter, READ_ACCESS); - count_access_for_types_in_expr(op1, non_escaping_records, counter, READ_ACCESS); -} - -void -count_access_for_types_in_expr(const_tree expr, const record_set &non_escaping_records, field_access_counter &counter, const enum access_code access) -{ - log("types in expr\n"); - gcc_assert(expr); - enum tree_code tree_code_expr = TREE_CODE(expr); - switch (tree_code_expr) - { - case COMPONENT_REF: count_access_for_type_in_component_ref(expr, non_escaping_records, counter, access); break; - case ADDR_EXPR: count_access_for_type_in_addr_expr(expr, non_escaping_records, counter, access); break; - case ARRAY_REF : count_access_for_type_in_array_expr(expr, non_escaping_records, counter, access); break; - default: break; - } -} - -void -count_access_for_types_in_lhs(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter) -{ - gcc_assert(stmt); - const enum gimple_code gimple_code_stmt = gimple_code(stmt); - const bool is_assign = GIMPLE_ASSIGN == gimple_code_stmt; - const bool is_call = GIMPLE_CALL == gimple_code_stmt; - const bool is_valid = is_assign || is_call; - gcc_assert(is_valid); - - - const_tree lhs = is_assign ? gimple_assign_lhs (stmt) : gimple_call_lhs (stmt); - /* GIMPLE_CALL might have a lhs null. - * E.g. - * foo() - */ - if (!lhs) return; - - count_access_for_types_in_expr(lhs, non_escaping_records, counter, WRITE_ACCESS); -} - -void -count_access_for_types_in_rhs(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter) -{ - gcc_assert(stmt); - const enum gimple_code gimple_code_stmt = gimple_code(stmt); - const bool is_assign = GIMPLE_ASSIGN == gimple_code_stmt; - gcc_assert(is_assign); - - log("types in rhs\n"); - const enum gimple_rhs_class gimple_rhs_class_stmt = gimple_assign_rhs_class(stmt); - switch (gimple_rhs_class_stmt) - { - case GIMPLE_TERNARY_RHS: - { - log("gimple_ternary_rhs\n"); - } - /* fall through */ - case GIMPLE_BINARY_RHS: - { - log("gimple_binary_rhs\n"); - } - /* fall through */ - case GIMPLE_SINGLE_RHS: - case GIMPLE_UNARY_RHS: - { - const_tree rhs1 = gimple_assign_rhs1(stmt); - gcc_assert(rhs1); - count_access_for_types_in_expr(rhs1, non_escaping_records, counter, READ_ACCESS); - log("gimple_single_rhs\n"); - } - break; - default: - gcc_unreachable(); - break; - } -} - -inline static void -is_gimple_assign_p(gimple *stmt) -{ - gcc_assert(stmt); - const enum gimple_code code = gimple_code(stmt); - const bool is_assign = GIMPLE_ASSIGN == code; - gcc_assert(is_assign); -} - -inline static void -is_gimple_call_p(gimple *stmt) -{ - gcc_assert(stmt); - const enum gimple_code code = gimple_code(stmt); - const bool is_call = GIMPLE_CALL == code; - gcc_assert(is_call); - -} - -void -count_access_for_types_in_assign(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter) -{ - is_gimple_assign_p(stmt); - - count_access_for_types_in_rhs(stmt, non_escaping_records, counter); - count_access_for_types_in_lhs(stmt, non_escaping_records, counter); -} - -static void -count_access_for_types_in_call_rhs(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter) -{ - is_gimple_call_p(stmt); - unsigned args = gimple_call_num_args (stmt); - - - - for (unsigned i = 0; i < args; i++) - { - const_tree arg = gimple_call_arg (stmt, i); - count_access_for_types_in_expr(arg, non_escaping_records, counter, READ_ACCESS); - } - -} - -void -count_access_for_types_in_call(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter) -{ - is_gimple_call_p(stmt); - count_access_for_types_in_lhs(stmt, non_escaping_records, counter); - - /* TODO: We need to iterate over each argument and find out if it is a read */ - count_access_for_types_in_call_rhs(stmt, non_escaping_records, counter); -} - -void -count_access_for_types_in_stmt(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter) -{ - gcc_assert(stmt); - const enum gimple_code gimple_code_stmt = gimple_code(stmt); - switch(gimple_code_stmt) - { - case GIMPLE_ASSIGN: - count_access_for_types_in_assign(stmt, non_escaping_records, counter); - break; - case GIMPLE_CALL: - count_access_for_types_in_call(stmt, non_escaping_records, counter); - break; - default: - break; - } -} - -void -count_access_for_types_in_bb(basic_block bb, const record_set &non_escaping_records, field_access_counter &counter) -{ - gcc_assert(bb); - for (gimple_stmt_iterator gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) - { - gimple *stmt = gsi_stmt(gsi); - count_access_for_types_in_stmt(stmt, non_escaping_records, counter); - } -} - -void -count_access_for_types_in_function(cgraph_node *cnode, const record_set &non_escaping_records, field_access_counter &counter) -{ - gcc_assert(cnode); - tree decl = cnode->decl; - gcc_assert(decl); - function *func = DECL_STRUCT_FUNCTION (decl); - gcc_assert(func); - push_cfun(func); - basic_block bb = NULL; - FOR_EACH_BB_FN (bb, func) - { - gcc_assert(bb); - count_access_for_types_in_bb(bb, non_escaping_records, counter); - } - pop_cfun(); -} - -void -init_field_access_counter(field_access_counter &counter, const record_set &non_escaping_records) -{ - for (auto it = non_escaping_records.cbegin(); it != non_escaping_records.cend(); ++it) - { - const_tree record = *it; - gcc_assert(record); - enum tree_code tree_code_record_type = TREE_CODE(record); - const bool is_record_type = RECORD_TYPE == tree_code_record_type; - gcc_assert(is_record_type); - - for (tree field = TYPE_FIELDS (record); field; field = DECL_CHAIN (field)) - { - gcc_assert(field); - const std::pair<const_tree, const_tree> struct_field_pair = std::make_pair(record, field); - counter[struct_field_pair] = { 0, 0 }; - } - } -} - -/* INFO: - * Yes, I know we are returning a std::map. - * Bad pattern? Maybe, but this will only be called once - * and I rather pass by value because that allows - * me to have a pure function and not worry about - * garbage collection - * - * TODO: I'd like to change type_map for a std::map - * TODO: I'd like to make this a template that can work - * for std::map and std::set - */ -field_access_counter -count_access_for_types_in_linking_unit(const record_set &non_escaping_records) -{ - field_access_counter counter; - init_field_access_counter(counter, non_escaping_records); - cgraph_node *cnode = NULL; - FOR_EACH_DEFINED_FUNCTION(cnode) - { - gcc_assert(cnode); - log("printing a defined function\n"); - print_function(cnode); - count_access_for_types_in_function(cnode, non_escaping_records, counter); - } - return counter; -} - -bool -_calculate_non_escaping_records(const_tree const &type, escaping_info *info, record_set *non_escaping_records) -{ - - gcc_assert(info); - log("NOW: %s is escaping %s\n", get_type_name(type), info->is_escaping ? "true" : "false"); - if (info->is_escaping) return true; - gcc_assert(non_escaping_records); - - enum tree_code tree_code_type = TREE_CODE(type); - const bool is_record_type = RECORD_TYPE == tree_code_type; - log("NOW: %s is record %s\n", get_type_name(type), is_record_type ? "true" : "false"); - if (!is_record_type) return true; - - non_escaping_records->insert(type); - return true; -} - -/* - * Yes, again, we are passing a std::set - * as a value. I don\t care too much since - * this is only called once... - */ -static record_set -calculate_non_escaping_records(type_map &escaping_type_info) -{ - // We are going to have to traverse the type_map... - // This is why I don't really like hash_set... - record_set non_escaping_records; - escaping_type_info.traverse<record_set*, _calculate_non_escaping_records>(&non_escaping_records); - return non_escaping_records; -} - -static field_access_counter -count_field_accesses() -{ - - type_map escaping_types; - calculate_escaping_types(escaping_types); - const record_set non_escaping_records = calculate_non_escaping_records(escaping_types); - field_access_counter counter = count_access_for_types_in_linking_unit(non_escaping_records); - return counter; -} - -record_field_set -get_fields_to_reorg() -{ - const field_access_counter counter = count_field_accesses(); - record_field_set records_and_fields_to_reorg; - for (auto it = counter.cbegin(); it != counter.cend(); ++it) - { - fields record_field_pair = it->first; - accesses counter = it->second; - const_tree record = record_field_pair.first; - const_tree field = record_field_pair.second; - // We are interested in reads == 0; - unsigned reads = counter.first; - log("final count for %s.%s = %d\n", get_type_name(record), get_field_name(field), reads); - if (0 != reads) continue; - - records_and_fields_to_reorg.insert(record_field_pair); - } - - return records_and_fields_to_reorg; -} - -static void -print_record_field_set(const record_field_set &to_reorg) -{ - log("I am about to print\n"); - for (auto it = to_reorg.cbegin(); it != to_reorg.cend(); ++it) - { - fields record_field_pair = *it; - const_tree record = record_field_pair.first; - const_tree field = record_field_pair.second; - // TODO: Some fields / records might be anonymous - log("will eliminate %s.%s\n", get_type_name(record), get_field_name(field)); - } -} - - -static unsigned int -iphw_execute() -{ - const record_field_set to_reorg = get_fields_to_reorg(); - log("I am about to enter print function\n"); - print_record_field_set(to_reorg); - return 0; -} - -namespace { -const pass_data pass_data_ipa_hello_world = -{ - SIMPLE_IPA_PASS, - "hello-world", - OPTGROUP_NONE, - TV_NONE, - (PROP_cfg | PROP_ssa), - 0, - 0, - 0, - 0, -}; - -class pass_ipa_hello_world : public simple_ipa_opt_pass -{ -public: - pass_ipa_hello_world (gcc::context *ctx) - : simple_ipa_opt_pass(pass_data_ipa_hello_world, ctx) - {} - - virtual bool gate(function*) { return flag_ipa_hello_world; } - virtual unsigned execute (function*) { return iphw_execute(); } -}; -} // anon namespace - -simple_ipa_opt_pass* -make_pass_ipa_hello_world (gcc::context *ctx) -{ - return new pass_ipa_hello_world (ctx); -} diff --git a/gcc/ipa-hello-world.h b/gcc/ipa-hello-world.h deleted file mode 100644 index e001ac17041..00000000000 --- a/gcc/ipa-hello-world.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef GCC_IPA_HELLO_WORLD_H -#define GCC_IPA_HELLO_WORLD_H -#pragma once - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tree.h" - -#include <set> - -//TODO: do not use pair. -//This names are unintelligible -typedef std::pair<const_tree /* record */, const_tree /* field */> fields; -typedef std::set<fields> record_field_set; -record_field_set get_fields_to_reorg(); - -#endif diff --git a/gcc/ipa-str-reorg-dead-field-eliminate.c b/gcc/ipa-str-reorg-dead-field-eliminate.c index 2e192328ad8..f918974f719 100644 --- a/gcc/ipa-str-reorg-dead-field-eliminate.c +++ b/gcc/ipa-str-reorg-dead-field-eliminate.c @@ -50,7 +50,6 @@ along with GCC; see the file COPYING3. If not see #include "ipa-structure-reorg.h" #include "ipa-utils.h" #include "ipa-str-reorg-utils.h" -#include "ipa-hello-world.h" #include "gimple-caster.hpp" @@ -67,6 +66,7 @@ along with GCC; see the file COPYING3. If not see } +/* static void log_expr_prologue (const int indent, const char *debug_str, tree expr) { @@ -609,6 +609,7 @@ is_interesting_struct_escape_analysis(const_tree record) if (is_blacklisted) return false; } + */ /* bool is_whitelisted = false; for (int i = 0; i < 4; i++) @@ -618,6 +619,7 @@ is_interesting_struct_escape_analysis(const_tree record) if (!is_whitelisted) return false; */ + /* bool in_set = #if __cplusplus > 201703L @@ -739,6 +741,7 @@ is_interesting_field_escape_analysis(const_tree field) is_field_decl_p(field); const char* field_name = get_field_name(field); + */ /* const char* whitelist [2] = { "nextin", "nextout" }; @@ -750,6 +753,7 @@ is_interesting_field_escape_analysis(const_tree field) if (!is_whitelisted) return false; */ + /* const bool in_set = #if __cplusplus > 201703L interesting_fields.contains(field_name); @@ -1058,7 +1062,7 @@ collect_global_declaration (varpool_node *vnode, int i; struct ipa_ref *ref; - /* Only IPA_REF_STORE and IPA_REF_LOAD left. */ + for (i = 0; vnode->iterate_referring (i, ref); i++) { bool filter_out = (*filter) (vnode->decl, decl_map); @@ -1144,12 +1148,6 @@ make_new_record_based_on_typedef (const_tree _typedef, t_map *mod_type_map) return new_type; } -/* - * This method will copy the parameter - * and delete the field named "delete_me" - * int the copy. The offsets will be adjusted - * to account for the deleted parameter - */ static const_tree make_new_record_based_on_old (const_tree old, t_map *mod_type_map) @@ -2205,13 +2203,11 @@ rewrite_assign_rhs (gimple *stmt, gimple_stmt_iterator &gsi, tree rhs3 = gimple_assign_rhs3 (stmt); is_stmt_rewritten |= rewrite_expr (rhs3, type_map, 0); } - /* fall through */ case GIMPLE_BINARY_RHS: { tree rhs2 = gimple_assign_rhs2 (stmt); is_stmt_rewritten |= rewrite_expr (rhs2, type_map, 0); } - /* fall through */ case GIMPLE_SINGLE_RHS: case GIMPLE_UNARY_RHS: { @@ -2596,7 +2592,6 @@ rewrite_global_decl (varpool_node *vnode, int i; struct ipa_ref *ref; - /* Only IPA_REF_STORE and IPA_REF_LOAD left. */ for (i = 0; vnode->iterate_referring (i, ref); i++) { test_log ("rewriting global declaration", 0); @@ -2763,6 +2758,8 @@ str_reorg_dead_field_eliminate (__attribute__((unused)) Info *info) return iphw_execute (); } +*/ + #if USE_NEW_INTERFACE int str_reorg_dead_field_eliminate_qual (Info *info) diff --git a/gcc/ipa-type-escape-analysis.c b/gcc/ipa-type-escape-analysis.c deleted file mode 100644 index dfaf859ae71..00000000000 --- a/gcc/ipa-type-escape-analysis.c +++ /dev/null @@ -1,962 +0,0 @@ -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "backend.h" -#include "options.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-cfg.h" -#include "gimple-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 "gimple.h" -#include "cfg.h" // needed for gimple-iterator.h -#include "gimple-iterator.h" -#include <stdbool.h> - -#include "ipa-str-reorg-utils.h" -#include "ipa-type-escape-analysis.h" - - -// First we need to collect all types - -static bool filter_type (type_map &escape_map, const_tree type); - -void update_escape_info (const_tree type, type_map &escape_map, bool is_escaping, escaping_reason reason); - -static const escaping_reason null_reason = { 0, 0, 0, 0 }; -inline escaping_reason -new_escaping_reason() -{ - return null_reason; -} - -//TODO: -// Should we be using C++? -escaping_reason -union_op(const escaping_reason &left, const escaping_reason &right) -{ - escaping_reason retval; - retval.global_is_visible = left.global_is_visible | right.global_is_visible; - retval.parameter_is_visible = left.parameter_is_visible | right.parameter_is_visible; - retval.return_is_visible = left.return_is_visible | right.return_is_visible;; - retval.type_is_casted = left.type_is_casted | right.type_is_casted;; - return retval; -} - -void -explain_print(escaping_reason reason) -{ - if (reason.global_is_visible) log("global is visible"); - if (reason.parameter_is_visible) log(", parameter is visible"); - if (reason.return_is_visible) log(", return is visible"); - if (reason.type_is_casted) log(", type is casted"); - log("\n"); -} - -void -update_escape_info_pointer (const_tree pointer_type, type_map &escape_map, bool is_escaping, escaping_reason reason) -{ - gcc_assert(pointer_type); - enum tree_code tree_code_pointer_type = TREE_CODE(pointer_type); - bool is_pointer_type = POINTER_TYPE == tree_code_pointer_type; - gcc_assert(is_pointer_type); - - escaping_info *info = escape_map.get(pointer_type); - if (!info) { log("no info\n"); return;} - - info->is_escaping |= is_escaping; - info->reason = union_op(info->reason, reason); - tree tree_type_pointer_type = TREE_TYPE(pointer_type); - gcc_assert(tree_type_pointer_type); - update_escape_info (tree_type_pointer_type, escape_map, info->is_escaping, info->reason); -} - -void -update_escape_info_array (const_tree array_type, type_map &escape_map, bool is_escaping, escaping_reason reason) -{ - gcc_assert(array_type); - enum tree_code tree_code_array_type = TREE_CODE(array_type); - bool is_array_type = ARRAY_TYPE == tree_code_array_type; - gcc_assert(is_array_type); - - escaping_info *info = escape_map.get(array_type); - if (!info) { log("no info\n"); return;} - - info->is_escaping |= is_escaping; - info->reason = union_op(info->reason, reason); - tree tree_type_array_type = TREE_TYPE(array_type); - gcc_assert(tree_type_array_type); - update_escape_info (tree_type_array_type, escape_map, info->is_escaping, info->reason); -} - -void -update_escape_info_record (const_tree record_type, type_map &escape_map, bool is_escaping, escaping_reason reason) -{ - gcc_assert(record_type); - enum tree_code tree_code_record_type = TREE_CODE(record_type); - bool is_record_type = RECORD_TYPE == tree_code_record_type; - gcc_assert(is_record_type); - - escaping_info *info = escape_map.get(record_type); - // we are collecting records, therefore, we **must** have - // it in the escaping info - //FIXME: Is this true? According to creduce bug, no. - gcc_assert(info); - info->is_escaping |= is_escaping; - info->reason = union_op(info->reason, reason); - - - for (tree field = TYPE_FIELDS (record_type); field; field = DECL_CHAIN (field)) - { - gcc_assert(field); - tree tree_type_field = TREE_TYPE(field); - gcc_assert(tree_type_field); - update_escape_info (tree_type_field, escape_map, info->is_escaping, info->reason); - } -} - -void -update_escape_info (const_tree type, type_map &escape_map, bool is_escaping, escaping_reason reason) -{ - // INFO: This is an optimization. - if (!is_escaping) { log("is not escaping\n"); return; } - - gcc_assert(type); - enum tree_code tree_code_type = TREE_CODE(type); - // We need to make sure that we are only dealing with - // the main type and not typedefs... - switch (tree_code_type) - { - case ARRAY_TYPE: - update_escape_info_array(type, escape_map, is_escaping, reason); - break; - case POINTER_TYPE: - update_escape_info_pointer(type, escape_map, is_escaping, reason); - break; - case RECORD_TYPE: - update_escape_info_record(type, escape_map, is_escaping, reason); - break; - default: - break; - } -} - -static bool -filter_pointer (type_map &escape_map, const_tree pointer) -{ - enum tree_code code = TREE_CODE (pointer); - gcc_assert(POINTER_TYPE == code); - const_tree base_type = TREE_TYPE(pointer); - return filter_type (escape_map, base_type); -} - -static bool -filter_array (type_map &escape_map, const_tree array) -{ - enum tree_code code = TREE_CODE (array); - gcc_assert(ARRAY_TYPE == code); - const_tree base_type = TREE_TYPE(array); - return filter_type (escape_map, base_type); -} - -static bool -filter_record (type_map &escape_map, const_tree record) -{ - log("filtering record %s\n", get_type_name(record)); - gcc_assert(record); - enum tree_code code = TREE_CODE(record); - gcc_assert(RECORD_TYPE == code); - - for (tree field = TYPE_FIELDS (record); field; field = DECL_CHAIN (field)) - { - tree field_type = TREE_TYPE(field); - gcc_assert(field_type); - filter_type(escape_map, field_type); - } - - return false; -} - -static bool -filter_type (type_map &escape_map, const_tree type) -{ - log("inside filter_type\n"); - - if (!type) return true; - - bool retval = true; - enum tree_code code = TREE_CODE(type); - switch (code) - { - case ARRAY_TYPE: retval = filter_array(escape_map, type); break; - case POINTER_TYPE: retval = filter_pointer(escape_map, type); break; - case RECORD_TYPE: retval = filter_record(escape_map, type); break; - default: break; - } - - - log("filter_type %s boring ? %s\n", get_type_name(type), retval ? "true" : "false"); - if (retval) return retval; - escaping_reason reason = new_escaping_reason(); - escaping_info info = { type , false , reason}; - escape_map.put(type, info); - return retval; -} - -static bool -filter_var_decl (type_map &escape_map, const_tree var_decl) -{ - log("filtering var_decl\n"); - gcc_assert(var_decl); - enum tree_code code = TREE_CODE(var_decl); - gcc_assert(code == VAR_DECL); - tree type = TREE_TYPE (var_decl); - gcc_assert(type); - return filter_type(escape_map, type); -} - -static bool -filter_parm_declarations (const_tree parm_decl, type_map &escape_map) -{ - gcc_assert(parm_decl); - enum tree_code code = TREE_CODE(parm_decl); - gcc_assert(PARM_DECL == code); - tree type = TREE_TYPE (parm_decl); - gcc_assert(type); - return filter_type(escape_map, type); -} - -static void -collect_global(type_map &escape_map, varpool_node *vnode) -{ - log("collect_global\n"); - gcc_assert(vnode); - - struct ipa_ref *ref = NULL; - for (int i = 0; vnode->iterate_referring (i, ref); i++) - { - log("inside vnode loop\n"); - tree decl = vnode->decl; - gcc_assert(decl); - enum tree_code code = TREE_CODE(decl); - gcc_assert(VAR_DECL == code); - bool filter_out = filter_var_decl(escape_map, decl); - if (filter_out) continue; - - tree type = TREE_TYPE(decl); - gcc_assert(type); - log("collecting global type escape analysis %s\n", get_type_name(type)); - escaping_reason reason = new_escaping_reason(); - escaping_info info = { type, false, reason }; - escape_map.put (type, info); - //escape_map.put (TYPE_MAIN_VARIANT(type), info); - } -} - -static void -collect_globals(type_map &escape_map) -{ - varpool_node *vnode; - FOR_EACH_VARIABLE (vnode) - { - collect_global(escape_map, vnode); - } -} - -static void -collect_parm_declarations (cgraph_node *cnode, type_map &escape_map) -{ - gcc_assert(cnode); - log("does function %s have parameters?\n", cnode->name()); - for (tree parm = DECL_ARGUMENTS (cnode->decl); parm; parm = DECL_CHAIN (parm)) - { - tree type = TREE_TYPE(parm); - log("about to enter parameter type %s\n", get_type_name(type)); - bool filter_out = filter_parm_declarations (parm, escape_map); - if (filter_out) continue; - - log("putting parameter type %s\n", get_type_name(type)); - gcc_assert(type); - - escaping_reason reason = new_escaping_reason(); - escaping_info info = { type, false, reason }; - escape_map.put(type, info); - } -} - -static void -collect_local_declarations (cgraph_node *cnode, type_map &escape_map) -{ - gcc_assert(cnode); - int i = 0; - function *func = DECL_STRUCT_FUNCTION (cnode->decl); - cnode->get_untransformed_body (); - tree var_decl = NULL; - FOR_EACH_LOCAL_DECL (func, i, var_decl) - { - gcc_assert(var_decl); - bool filter_out = filter_var_decl(escape_map, var_decl); - if (filter_out) continue; - - tree tree_type = TREE_TYPE(var_decl); - gcc_assert(tree_type); - escaping_reason reason = new_escaping_reason(); - escaping_info info = { tree_type, false, reason}; - escape_map.put(tree_type, info); - } -} - -static void collect_expr (const_tree expr, type_map &escape_map); - -static void -collect_expr_in_component_ref(const_tree cref, type_map &escape_map) -{ - gcc_assert(cref); - const enum tree_code code = TREE_CODE(cref); - const bool is_cref = COMPONENT_REF == code; - gcc_assert(is_cref); - - const_tree _struct = TREE_OPERAND(cref, 0); - gcc_assert(_struct); - - const_tree _struct_type = TREE_TYPE(_struct); - log("we are in collect_expr_in_component_ref %s\n", get_type_name(_struct_type)); - escaping_reason reason = new_escaping_reason(); - escaping_info info = { _struct_type, false , reason}; - escape_map.put(_struct_type, info); - - collect_expr(_struct, escape_map); - -} - -static void -collect_expr (const_tree expr, type_map &escape_map) -{ - gcc_assert(expr); - enum tree_code tree_code_expr = TREE_CODE(expr); - switch (tree_code_expr) - { - case COMPONENT_REF: - collect_expr_in_component_ref(expr, escape_map); - break; - default: - break; - } -} - -static void -collect_pointer_plus (tree lhs, tree rhs1, tree rhs2, type_map &escape_map) -{ - log("collect_pointer_plus\n"); - const_tree lhs_type = lhs ? TREE_TYPE(lhs) : NULL; - bool is_lhs_boring = lhs_type ? filter_type(escape_map, lhs_type) : true; - const_tree rhs1_type = rhs1 ? TREE_TYPE(rhs1) : NULL; - bool is_rhs1_boring = rhs1_type ? filter_type(escape_map, rhs1_type) : true; - const_tree rhs2_type = rhs2 ? TREE_TYPE(rhs2) : NULL; - bool is_rhs2_boring = rhs2_type ? filter_type(escape_map, rhs2_type) : true; - - if (!is_lhs_boring) - { - escaping_reason reason = new_escaping_reason(); - escaping_info info = { lhs_type , false, reason }; - escape_map.put(lhs_type, info); - } - if (!is_rhs1_boring) - { - collect_expr(rhs1, escape_map); - } - if (!is_rhs2_boring) - { - collect_expr(rhs2, escape_map); - } -} - -static void -collect_assign_rhs (gimple *stmt, type_map &escape_map) -{ - enum tree_code code = gimple_expr_code (stmt); - switch (code) - { - case POINTER_PLUS_EXPR: - case POINTER_DIFF_EXPR: - case COMPONENT_REF: - { - tree rhs2 = gimple_assign_rhs2(stmt); - tree rhs1 = gimple_assign_rhs1(stmt); - tree lhs = gimple_assign_lhs (stmt); - collect_pointer_plus (lhs, rhs1, rhs2, escape_map); - break; - } - default: - break; - } -} - -static void -collect_assign (gimple *stmt, type_map &escape_map) -{ - gcc_assert(stmt); - collect_assign_rhs (stmt, escape_map); -} - -static void -collect_stmt (gimple *stmt, type_map &escape_map) -{ - gcc_assert (stmt); - const enum gimple_code code = gimple_code (stmt); - switch (code) - { - case GIMPLE_ASSIGN: - collect_assign(stmt, escape_map); - break; - default: - break; - } - - return; -} - -static void -collect_basic_block (basic_block bb, type_map &escape_map) -{ - gcc_assert(bb); - for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next(&gsi)) - { - gimple *stmt = gsi_stmt (gsi); - collect_stmt (stmt, escape_map); - } -} - -static void -collect_function_body (cgraph_node *cnode, type_map &escape_map) -{ - gcc_assert (cnode); - cnode->get_untransformed_body(); - basic_block bb = NULL; - tree decl = cnode->decl; - gcc_assert(decl); - function *func = DECL_STRUCT_FUNCTION (decl); - gcc_assert(func); - push_cfun(func); - FOR_EACH_BB_FN (bb, func) - { - gcc_assert(bb); - collect_basic_block (bb, escape_map); - } - pop_cfun(); -} - -static void -collect_return_type (cgraph_node *cnode, type_map &escape_map) -{ - gcc_assert(cnode); - - const_tree decl = cnode->decl; - const enum tree_code code = TREE_CODE(decl); - const bool is_function_decl = FUNCTION_DECL == code; - gcc_assert (is_function_decl); - - const_tree fn_type = TREE_TYPE (decl); - const enum tree_code fn_type_code = TREE_CODE(fn_type); - const bool is_fn_type = FUNCTION_TYPE == fn_type_code; - gcc_assert (is_fn_type); - - const_tree ret_type = TREE_TYPE(fn_type); - gcc_assert (ret_type); - - const bool is_boring = filter_type(escape_map, ret_type); - if (is_boring) return; - - escaping_reason reason = new_escaping_reason(); - escaping_info info = {ret_type, false, reason}; - escape_map.put(ret_type, info); - return; -} - -static void -collect_types(type_map &escape_map) -{ - collect_globals(escape_map); - - cgraph_node *cnode = NULL; - FOR_EACH_DEFINED_FUNCTION (cnode) - { - collect_function_body (cnode, escape_map); - collect_local_declarations (cnode, escape_map); - collect_parm_declarations (cnode, escape_map); - collect_return_type (cnode, escape_map); - } -} - -bool -_print_types( const_tree const &type, escaping_info *info, __attribute__((unused)) void*) -{ - log("collected,%s\n", get_type_name(type)); - bool is_escaping = info->is_escaping; - log("type %s is escaping %s : ", get_type_name(type), is_escaping ? "true" : "false"); - explain_print(info->reason); - return true; -} - -static void -print_types(type_map &escape_map) -{ - log("printing_types\n"); - escape_map.traverse<void*, _print_types> (NULL); -} - -static bool -is_variable_escaping(varpool_node *vnode) -{ - gcc_assert(vnode); - return vnode->externally_visible; -} - -static bool -is_function_escaping(const cgraph_node *cnode) -{ - gcc_assert(cnode); - return cnode->externally_visible; /* TODO: How are FOR_EACH_FUNCTION and FOR_EACH_DEFINED_FUNCTION different */ // || !cnode->definition; -} - -void calculate_escaping_parameters(const cgraph_node *cnode, type_map &escape_map, bool override = false); - -void -calculate_escaping_parameters(const cgraph_node *cnode, type_map &escape_map, bool override) -{ - gcc_assert(cnode); - tree function = cnode->decl; - gcc_assert(function); - enum tree_code code = TREE_CODE (function); - bool is_function_decl = FUNCTION_DECL == code; - gcc_assert (is_function_decl); - - bool is_escaping = is_function_escaping(cnode) || override; - function_args_iterator iter; - tree arg; - const_tree function_type = TREE_TYPE(function); - FOREACH_FUNCTION_ARGS (function_type, arg, iter) - { - //const_tree main_type = TYPE_MAIN_VARIANT(arg); - log("parameter type %s is escaping %s\n", get_type_name(arg), is_escaping ? "true" : "false"); - escaping_reason reason = new_escaping_reason(); - reason.parameter_is_visible = is_escaping; - update_escape_info(arg, escape_map, is_escaping, reason); - } -} -void is_return_type_escaping(const cgraph_node *cnode, type_map &escape_map, bool override = false); - -void -is_return_type_escaping(const cgraph_node *cnode, type_map &escape_map, bool override) -{ - gcc_assert(cnode); - bool is_escaping = is_function_escaping(cnode) || override; - tree function = cnode->decl; - gcc_assert(function); - enum tree_code code = TREE_CODE(function); - bool is_function = FUNCTION_DECL == code; - gcc_assert(is_function); - - tree tree_type = TREE_TYPE(function); - gcc_assert(tree_type); - tree return_type = TREE_TYPE(tree_type); - gcc_assert(return_type); - log("return type %s\n", get_type_name(return_type)); - - // void update_escaping_info (const_tree type, type_map &escape_map, bool is_escaping); -/*struct escaping_reason_s { - unsigned global_is_visible : 1; - unsigned function_is_visible : 1; -}; -*/ - escaping_reason reason = new_escaping_reason(); - reason.return_is_visible = is_escaping; - update_escape_info(return_type, escape_map, is_escaping, reason); - //escaping_info *info = escape_map.get(return_type); - // If there's no info it means it is not interesting... - //if (!info) return; - //info->is_escaping |= is_escaping; -} - - -bool -calculate_escaping_types_from_function_signatures ( - cgraph_node * const &cnode, type_map *escape_map) -{ - - gcc_assert(escape_map); - gcc_assert(cnode); - bool is_escaping = is_function_escaping(cnode); - log("function %s is escaping %s\n", cnode->name(), is_escaping ? "true" : "false"); - calculate_escaping_parameters(cnode, *escape_map, is_escaping); - is_return_type_escaping(cnode, *escape_map, is_escaping); - return true; -} - -void -find_calls_to_undefined_functions_from_call(gimple *stmt, hash_set<tree> &set, type_map &escape_map) -{ - gcc_assert(stmt); - const enum gimple_code code = gimple_code(stmt); - const bool is_gimple_call = GIMPLE_CALL == code; - gcc_assert(is_gimple_call); - - gcall *call = dyn_cast<gcall *>(stmt); - tree fn = gimple_call_fndecl(stmt); - - // Function pointer? - if (!fn) return; - - // if fn is in set... then it means that it is undefined. - if (!set.contains(fn)) return; - - unsigned num_arguments = gimple_call_num_args(call); - for (unsigned i = 0; i < num_arguments; i++) - { - tree argument = gimple_call_arg(stmt, i); - /* - // TODO: Why is this the case? - gimple *def_for_arg = SSA_NAME_DEF_STMT(argument); - gcc_assert(def_for_arg); - const enum gimple_code code2 = gimple_code(def_for_arg); - const bool is_gimple_call2 = GIMPLE_CALL == code2; - const bool is_gimple_assign = GIMPLE_ASSIGN == code2; - const bool is_assignable = is_gimple_call2 ^ is_gimple_assign; - gcc_assert(is_assignable); - - tree arg_var = is_gimple_assign ? gimple_assign_lhs(def_for_arg) : gimple_call_lhs(def_for_arg); - gcc_assert(arg_var); - */ - tree arg_type = TREE_TYPE(argument); - gcc_assert(arg_type); - - bool is_escaping = true; - escaping_reason reason = new_escaping_reason(); - reason.parameter_is_visible = is_escaping; - update_escape_info(arg_type, escape_map, is_escaping, reason); - } -} - -void -find_calls_to_undefined_functions_from_stmt(gimple *stmt, hash_set<tree> &set, type_map &escape_map) -{ - gcc_assert(stmt); - const enum gimple_code code = gimple_code (stmt); - const bool is_gimple_call = GIMPLE_CALL == code; - if (!is_gimple_call) return; - - find_calls_to_undefined_functions_from_call(stmt, set, escape_map); -} - - -void -find_calls_to_undefined_functions_from_bb(basic_block bb, hash_set<tree> &set, type_map &escape_map) -{ - gcc_assert(bb); - for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gimple *stmt = gsi_stmt (gsi); - find_calls_to_undefined_functions_from_stmt(stmt, set, escape_map); - } -} - -void -find_calls_to_undefined_functions_from_function(cgraph_node *cnode, hash_set<tree> &set, type_map &escape_map) -{ - gcc_assert(cnode); - cnode->get_untransformed_body (); - function *func = DECL_STRUCT_FUNCTION(cnode->decl); - basic_block bb = NULL; - push_cfun(func); - FOR_EACH_BB_FN(bb, func) - { - find_calls_to_undefined_functions_from_bb(bb, set, escape_map); - } - pop_cfun(); -} - -void -is_any_function_escaping(type_map &escape_map) -{ - cgraph_node *cnode = NULL; - hash_set<tree> not_defined_functions; - - FOR_EACH_FUNCTION (cnode) - { - gcc_assert(cnode); - const char* _free = "free"; - //const char* _memset = "memset"; - const char* _malloc = "malloc"; - const char* _realloc = "realloc"; - const char* _calloc= "calloc"; - const char* ob_name = cnode->name(); - if (strcmp(ob_name, _free) == 0) continue; - //if (strcmp(ob_name, _memset) == 0) continue; - if (strcmp(ob_name, _malloc) == 0) continue; - if (strcmp(ob_name, _realloc) == 0) continue; - if (strcmp(ob_name, _calloc) == 0) continue; - - not_defined_functions.add(cnode->decl); - } - - - FOR_EACH_DEFINED_FUNCTION(cnode) - { - gcc_assert(cnode); - cnode->get_untransformed_body(); - not_defined_functions.remove(cnode->decl); - calculate_escaping_types_from_function_signatures (cnode, &escape_map); - } - - // not_defined_functions.traverse<type_map *, calculate_escaping_types_from_function_signatures> (&escape_map); - //TODO: Walk gimple code and identify GIMPLE_CALL to see if function is not defined... - FOR_EACH_DEFINED_FUNCTION(cnode) - { - find_calls_to_undefined_functions_from_function(cnode, not_defined_functions, escape_map); - } -} - -void -is_any_variable_escaping(type_map &escape_map) -{ - varpool_node *vnode = NULL; - // Global variables - FOR_EACH_VARIABLE(vnode) - { - bool is_escaping = is_variable_escaping(vnode); - log("variable %s is escaping %s\n", vnode->name(), is_escaping ? "true" : "false"); - tree decl = vnode->decl; - gcc_assert(decl); - tree type = TREE_TYPE(decl); - gcc_assert(type); - // void update_escaping_info (const_tree type, type_map &escape_map, bool is_escaping); - escaping_reason reason = new_escaping_reason(); - reason.global_is_visible = is_escaping; - update_escape_info (type, escape_map, is_escaping, reason); - //escaping_info *info = escape_map.get(type); - //if (!info) return; - //info->is_escaping |= is_escaping; - } -} - -//TODO: place in header file -inline static void -print_function (cgraph_node *cnode) -{ - if (!dump_file) - return; - gcc_assert (cnode); - cnode->get_untransformed_body (); - dump_function_to_file (cnode->decl, dump_file, TDF_NONE); -} - -static bool -cast_to_void_in_assign(const_tree lhs, const_tree rhs, type_map &escape_map) -{ - gcc_assert(lhs); - gcc_assert(rhs); - const_tree tree_type_lhs = TREE_TYPE(lhs); - gcc_assert(tree_type_lhs); - const_tree tree_type_rhs = TREE_TYPE(rhs); - gcc_assert(tree_type_rhs); - const char* const type_name_lhs = get_type_name(tree_type_lhs); - const char* const type_name_rhs = get_type_name(tree_type_rhs); - enum tree_code tree_code_rhs = TREE_CODE(rhs); - bool is_ssa_name = SSA_NAME == tree_code_rhs; - bool is_var_decl = VAR_DECL == tree_code_rhs; - bool is_var_decl_or_ssa_name = is_ssa_name || is_var_decl; - log("lhs = %s, rhs = %s\n", type_name_lhs, type_name_rhs); - if (!is_var_decl_or_ssa_name) return false; - - // We need to find out the base... - const_tree base_type_lhs = get_base_type(tree_type_lhs); - gcc_assert(base_type_lhs); - const_tree base_type_rhs = get_base_type(tree_type_rhs); - gcc_assert(base_type_rhs); - // TODO: FIXME: - // Is this always correct? I think this can only happen - // if we are mallocing and friends... - enum tree_code tree_code_base_type_rhs = TREE_CODE(base_type_rhs); - if (tree_code_base_type_rhs == VOID_TYPE) return false; - - bool is_casting_stmt = TYPE_MAIN_VARIANT(base_type_lhs) != TYPE_MAIN_VARIANT(base_type_rhs); - log("is casting stmt ? %s\n", is_casting_stmt ? "true" : "false"); - if (!is_casting_stmt) return false; - - log("escaping lhs %s\n", type_name_lhs); - escaping_reason reason = new_escaping_reason(); - reason.type_is_casted = is_casting_stmt; - update_escape_info(tree_type_lhs, escape_map, is_casting_stmt, reason); - - log("escaping rhs %s\n", type_name_rhs); - update_escape_info(tree_type_rhs, escape_map, is_casting_stmt, reason); - return true; -} - -static void -cast_to_void_in_assign (gimple *stmt, type_map &escape_map) -{ - enum gimple_code gcode = gimple_code (stmt); - const char* const gcode_str = gimple_code_name[gcode]; - gcc_assert(gcode_str); - - switch (gimple_assign_rhs_class (stmt)) - { - case GIMPLE_SINGLE_RHS: - case GIMPLE_UNARY_RHS: - { - tree lhs = gimple_assign_lhs(stmt); - tree rhs = gimple_assign_rhs1(stmt); - bool retval = cast_to_void_in_assign(lhs, rhs, escape_map); - if (!retval) break; - - tree tree_type_lhs = TYPE_MAIN_VARIANT(TREE_TYPE(lhs)); - tree tree_type_rhs = TYPE_MAIN_VARIANT(TREE_TYPE(rhs)); - const char* const type_name_lhs = get_type_name(tree_type_lhs); - const char* const type_name_rhs = get_type_name(tree_type_rhs); - log("type casting %s != %s ", type_name_lhs, type_name_rhs); - if (dump_file) print_gimple_stmt (dump_file, stmt, 0, TDF_NONE); - log("\n"); - } - default: - break; - } -} - -static void -cast_to_void_in_stmt (gimple *stmt, type_map &escape_map) -{ - gcc_assert (stmt); - const enum gimple_code code = gimple_code (stmt); - switch (code) - { - case GIMPLE_ASSIGN: - cast_to_void_in_assign(stmt, escape_map); - break; - default: - break; - } - - return; -} - -static void -cast_to_void_in_bb(basic_block bb, type_map &escape_map) -{ - gcc_assert(bb); - for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next(&gsi)) - { - gimple *stmt = gsi_stmt (gsi); - cast_to_void_in_stmt (stmt, escape_map); - } -} - -static void -cast_to_void_in_function(cgraph_node *cnode, type_map &escape_map) -{ - gcc_assert (cnode); - print_function (cnode); - basic_block bb = NULL; - tree decl = cnode->decl; - gcc_assert(decl); - function *func = DECL_STRUCT_FUNCTION (decl); - gcc_assert(func); - push_cfun(func); - FOR_EACH_BB_FN (bb, func) - { - gcc_assert(bb); - cast_to_void_in_bb(bb, escape_map); - } - pop_cfun(); -} - -static void -cast_to_void_in_program(type_map &escape_map) -{ - cgraph_node *cnode = NULL; - FOR_EACH_DEFINED_FUNCTION (cnode) - { - gcc_assert(cnode); - cnode->get_untransformed_body(); - cast_to_void_in_function(cnode, escape_map); - } -} - -/* INFO: - * Yes, I know we are returning a std::map. - * Bad pattern? Maybe, but this will only be called once - * and I rather pass by value because that allows - * me to have a pure function and not worry about - * garbage collection - * - * TODO: I'd like to change type_map for a std::map - * TODO: I'd like to make this a template that can work - * for std::map and std::set - */ -void -calculate_escaping_types(type_map &escape_map) -{ - collect_types(escape_map); - is_any_variable_escaping(escape_map); - is_any_function_escaping(escape_map); - cast_to_void_in_program(escape_map); - print_types(escape_map); -} - -static unsigned int -iphw_execute() -{ - // We can ignore the return value here... - type_map escape_map; - calculate_escaping_types(escape_map); - return 0; -} - - -namespace { -const pass_data pass_data_ipa_type_escape_analysis = -{ - SIMPLE_IPA_PASS, - "type-escape-analysis", - OPTGROUP_NONE, - TV_NONE, - (PROP_cfg | PROP_ssa), - 0, - 0, - 0, - 0, -}; - -class pass_ipa_type_escape_analysis : public simple_ipa_opt_pass -{ -public: - pass_ipa_type_escape_analysis (gcc::context *ctx) - : simple_ipa_opt_pass(pass_data_ipa_type_escape_analysis, ctx) - {} - - virtual bool gate(function*) { return in_lto_p && flag_ipa_type_escape_analysis; } - virtual unsigned execute (function*) { return iphw_execute(); } -}; -} // anon namespace - -simple_ipa_opt_pass* -make_pass_ipa_type_escape_analysis (gcc::context *ctx) -{ - return new pass_ipa_type_escape_analysis (ctx); -} diff --git a/gcc/ipa-type-escape-analysis.h b/gcc/ipa-type-escape-analysis.h deleted file mode 100644 index 7dcda948189..00000000000 --- a/gcc/ipa-type-escape-analysis.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef GCC_IPA_TYPE_ESCAPE_ANALYSIS_H -#define GCC_IPA_TYPE_ESCAPE_ANALYSIS_H -#pragma once - -struct escaping_reason_s { - unsigned global_is_visible : 1; - unsigned parameter_is_visible : 1; - unsigned return_is_visible : 1; - unsigned type_is_casted : 1; -}; -typedef struct escaping_reason_s escaping_reason; - -struct escaping_info_s { const_tree type; bool is_escaping; escaping_reason reason; }; -typedef struct escaping_info_s escaping_info; -//TODO: Maybe change this to a std::map? -//Can we get an idea of what conventions gcc want? -//Maybe I should ask... -typedef hash_map<const_tree, escaping_info> type_map; -void calculate_escaping_types(type_map&); - -#endif diff --git a/gcc/passes.def b/gcc/passes.def index b4c0fa0d3c1..4c8391281f2 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -149,8 +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_type_escape_analysis); - NEXT_PASS (pass_ipa_hello_world); NEXT_PASS (pass_ipa_cp); NEXT_PASS (pass_ipa_sra); NEXT_PASS (pass_ipa_cdtor_merge); diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 25fccb80f31..ddf1edb9c90 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -502,8 +502,6 @@ extern ipa_opt_pass_d *make_pass_ipa_fn_summary (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_inline (gcc::context *ctxt); 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_prototype (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); |