diff options
author | Erick Ochoa <erick.ochoa@theobroma-systems.com> | 2020-05-22 14:17:54 +0200 |
---|---|---|
committer | Erick Ochoa <erick.ochoa@theobroma-systems.com> | 2020-06-03 16:05:59 +0200 |
commit | e1628477901c83e16e778a945268c11bbcfe215b (patch) | |
tree | ba144f88cfb33bc469ef973b54145fd4f21a831a | |
parent | f5971bc5694541fe716bafe052f352856dcc379c (diff) |
improving escape analysis
-rw-r--r-- | gcc/collect-types.c | 46 | ||||
-rw-r--r-- | gcc/compare-types.c | 15 | ||||
-rw-r--r-- | gcc/ipa-hello-world.c | 33 | ||||
-rw-r--r-- | gcc/ipa-hello-world.h | 3 | ||||
-rw-r--r-- | gcc/ipa-type-collector.c | 14 |
5 files changed, 85 insertions, 26 deletions
diff --git a/gcc/collect-types.c b/gcc/collect-types.c index 894a755cd5f..a719185dc0a 100644 --- a/gcc/collect-types.c +++ b/gcc/collect-types.c @@ -68,30 +68,36 @@ filter_boring_types_pointer(const_tree type, ptrset_t &types) } static bool -filter_boring_types_record(const_tree type, ptrset_t &types) -{ - assert_is_type(type, RECORD_TYPE); - return false; -} - -static bool -filter_boring_types_unions(const_tree type, ptrset_t &types) +filter_boring_types_union_or_record(const_tree type, ptrset_t &types) { const enum tree_code code = TREE_CODE(type); const bool is_union = UNION_TYPE == code; const bool is_qual_union = QUAL_UNION_TYPE == code; - const bool is_valid_input = is_union || is_qual_union; + const bool is_record = RECORD_TYPE == code; + const bool is_valid_input = is_union || is_qual_union || is_record; gcc_assert(is_valid_input); + bool is_boring = !is_record; for (tree field = TYPE_FIELDS(type) ; field ; field = DECL_CHAIN(field)) { const_tree field_type = TREE_TYPE(field); gcc_assert(field_type); - const bool is_boring = filter_boring_types(field_type, types); - if (!is_boring) return is_boring; + is_boring |= filter_boring_types(field_type, types); } - return true; + return is_boring; +} + +static bool +filter_boring_types_record(const_tree type, ptrset_t &types) +{ + return filter_boring_types_union_or_record(type, types); +} + +static bool +filter_boring_types_unions(const_tree type, ptrset_t &types) +{ + return filter_boring_types_union_or_record(type, types); } static bool @@ -171,13 +177,25 @@ filter_boring_types(const_tree type, ptrset_t &types) bool is_boring = true; enum tree_code code = TREE_CODE(type); + log ("filter \n"); 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: + is_boring = true; + break; case ARRAY_TYPE: is_boring = filter_boring_types_array(type, types); break; case RECORD_TYPE: is_boring = filter_boring_types_record(type, types); + is_boring = false; break; case UNION_TYPE: is_boring = filter_boring_types_union(type, types); @@ -198,7 +216,8 @@ filter_boring_types(const_tree type, ptrset_t &types) is_boring = filter_boring_types_method(type, types); break; default: - // I will probably need to fuzz. + log("tree_code: %s\n", get_tree_code_name(code)); + gcc_unreachable(); break; } @@ -225,7 +244,6 @@ collect_types_from_record_or_union_type(const_tree type, ptrset_t &types) const bool is_qual_union = QUAL_UNION_TYPE == code; const bool is_valid_input = is_record || is_union || is_qual_union; gcc_assert(is_valid_input); - assert_is_complete(type); for (tree field = TYPE_FIELDS(type) ; field ; field = DECL_CHAIN(field)) { diff --git a/gcc/compare-types.c b/gcc/compare-types.c index 2457b833d4e..e1bc8001127 100644 --- a/gcc/compare-types.c +++ b/gcc/compare-types.c @@ -213,7 +213,9 @@ eq_identifier(const_tree a, const_tree b) const int length_a = name_a.length(); const int length_b = name_b.length(); const bool is_sound_input = length_a > 0 || length_b > 0; - return is_sound_input && name_a.compare(name_b) == 0; + const bool retval = is_sound_input && name_a.compare(name_b) == 0; + log("eq_identifier = %s\n", retval ? "true" : "false"); + return retval; } static bool @@ -224,6 +226,7 @@ eq_structural(const_tree a, const_tree b, const bool force_structural) const enum tree_code code_b = TREE_CODE(b); const bool equal_code = code_a == code_b; if (!equal_code) return false; + log("equal codes \n"); const enum tree_code code = code_a; switch (code) @@ -241,6 +244,7 @@ eq_structural(const_tree a, const_tree b, const bool force_structural) case ENUMERAL_TYPE: case BOOLEAN_TYPE: case OFFSET_TYPE: + log("simple comparison is true\n"); return true; break; default: @@ -253,6 +257,7 @@ eq_structural(const_tree a, const_tree b, const bool force_structural) return eq_record_types(a, b, force_structural); break; case POINTER_TYPE: + log("pointer type\n"); return eq_pointer_types(a, b, force_structural); break; case REFERENCE_TYPE: @@ -320,15 +325,21 @@ eq_types(const_tree a, const_tree b, const bool force_structural) // eq_canonical (a-incomplete, a-complete) = false // Fallback to eq_identifier only here. // This should be the only static call to eq_identifier! + const bool is_a_incomplete = is_incomplete_type(a); const bool is_b_incomplete = is_incomplete_type(b); const bool compare_incomplete_types = is_a_incomplete || is_b_incomplete; + log("will compare incomplete types %s\n", compare_incomplete_types ? "true" : "false"); if (compare_incomplete_types) return eq_identifier(a, b); - if (eq_main_variant(a, b)) return true; + // Main variant is unreliable when we are comparing builtin types? + // comparing 0,64: {}* == 0,64:__gcov_info {0,32:integer_type;8,72: {}*;16,48:integer_type;24,88:integer_type*;32,544:void_type(0,64:integer_type*, 0,32:integer_type, 0,0:void_type)*[];96,128:integer_type;104,168:__gcov_fn_info {0,64: {}*;8,40:integer_type;12,44:integer_type;16,48:integer_type;24,280:__gcov_ctr_info {0,32:integer_type;8,72:integer_type*;}[];}**;}* + if (eq_main_variant(a, b) && eq_structural(a, b)) return true; + log("eq_main_variant returned false\n"); if (!eq_canonical(a, b)) return false; + log("eq_canonical returned true\n"); // optimistic... // maybe we should have a MAYBE? diff --git a/gcc/ipa-hello-world.c b/gcc/ipa-hello-world.c index 5e3be7a475d..e55f38aaf26 100644 --- a/gcc/ipa-hello-world.c +++ b/gcc/ipa-hello-world.c @@ -38,6 +38,14 @@ typedef std::set<const_tree> undefset; +void +Reason::print() const +{ + if (!this->is_escaping) return; + + log("g=%d p=%d r=%d c=%d v=%d u=%d\n", this->global_is_visible, this->parameter_is_visible, this->return_is_visible, this->type_is_casted, this->type_is_volatile, this->type_is_in_union); +} + Reason Reason::operator|(const Reason &other) { @@ -187,6 +195,10 @@ update_escape_info_function(const_tree type, ptrset_t &types, Reason reason, typ static void update_escape_info( const_tree type, ptrset_t &types, Reason reason, typemap &calc) { + if (!type) return; + + assert_type_is_in_universe(type, types); + #ifdef OPTIMIZED // if (!reason.is_escaping) return; // Above not necessarily true, since we might point to a union @@ -200,7 +212,6 @@ update_escape_info( const_tree type, ptrset_t &types, Reason reason, typemap &ca if (already_escaping) return; #endif - assert_type_is_in_universe(type, types); bool is_interesting = types.in_points_to_record(type); if (!is_interesting) return; @@ -228,7 +239,8 @@ update_escape_info( const_tree type, ptrset_t &types, Reason reason, typemap &ca update_escape_info_pointer(type, types, reason, calc); break; case FUNCTION_TYPE: - update_escape_info_function(type, types, reason, calc); + // We must not consider function pointers? + //update_escape_info_function(type, types, reason, calc); break; case METHOD_TYPE: default: @@ -274,9 +286,8 @@ filter_known_function(cgraph_node *node) const char *_malloc = "malloc"; const char *_realloc = "realloc"; const char *_calloc = "calloc"; + const char *_memset = "memset"; const char *name = node->name(); - // TODO: we want memset here... - // but we can't until we fix the sizeof tree... gcc_assert(name); filter |= strcmp(_free, name) == 0; filter |= strcmp(_malloc, name) == 0; @@ -288,6 +299,9 @@ filter_known_function(cgraph_node *node) static bool is_function_escaping(cgraph_node *cnode) { + const bool filter = filter_known_function(cnode); + if (filter) return false; + gcc_assert(cnode); return cnode->externally_visible; } @@ -418,6 +432,9 @@ calculate_escaping_types_from_call_rhs(ptrset_t &types, typemap &calc, undefset const bool is_undefined = undef.find(fn) != undef.end(); if (!is_undefined) return; + tree decl_name = DECL_NAME(fn); + const char* identifier = IDENTIFIER_POINTER(decl_name); + log("looking at function %s\n", identifier); Reason reason {}; reason.is_escaping = is_undefined; reason.parameter_is_visible = is_undefined; @@ -428,6 +445,7 @@ calculate_escaping_types_from_call_rhs(ptrset_t &types, typemap &calc, undefset const_tree arg_i = gimple_call_arg(call, i); gcc_assert(arg_i); const_tree type_i = TREE_TYPE(arg_i); + log("argument type %s (or %s)\n", get_type_identifier(type_i).c_str(), type_to_string(type_i).c_str()); update_escape_info(type_i, types, reason, calc); } } @@ -440,8 +458,8 @@ calculate_escaping_types_from_call(ptrset_t &types, typemap &calc, undefset &und tree fn = gimple_call_fndecl(stmt); if (!fn) return; - const bool is_undefined = undef.find(fn) != undef.end(); - if (!is_undefined) return; + const bool in_set = undef.find(fn) != undef.end(); + if (!in_set) return; calculate_escaping_types_from_call_lhs(types, calc, undef, stmt); calculate_escaping_types_from_call_rhs(types, calc, undef, stmt); @@ -572,7 +590,8 @@ print_escaping_types(typemap &calc) { const_tree type = i->first; const Reason reason = i->second; - log ("escaping: %s = %s\n", get_type_identifier(type).c_str(), reason.is_escaping ? "true" : "false"); + log ("escaping: %s (or %s) = %s\n", get_type_identifier(type).c_str(), type_to_string(type).c_str(), reason.is_escaping ? "true" : "false"); + reason.print(); } } diff --git a/gcc/ipa-hello-world.h b/gcc/ipa-hello-world.h index 44b44d82828..c55968162e3 100644 --- a/gcc/ipa-hello-world.h +++ b/gcc/ipa-hello-world.h @@ -10,7 +10,8 @@ struct Reason { bool type_is_in_union : 1; Reason operator|(const Reason &); Reason& operator|=(const Reason &); - Reason() {}; + void print() const; + Reason() : is_escaping(0), global_is_visible(0), parameter_is_visible(0), type_is_casted(0), type_is_volatile(0), type_is_in_union(0) {}; }; //typedef std::map<const_tree, Reason> typemap; diff --git a/gcc/ipa-type-collector.c b/gcc/ipa-type-collector.c index d8a5c1dfa6b..e8c3130a74a 100644 --- a/gcc/ipa-type-collector.c +++ b/gcc/ipa-type-collector.c @@ -151,12 +151,18 @@ collect_types_from_ssa_name(const_tree expr, ptrset_t &types) static void collect_types_from_var_decl(const_tree expr, ptrset_t &types) { + location_t loc = DECL_SOURCE_LOCATION(expr); + const bool is_builtin = BUILTINS_LOCATION == loc; + if (is_builtin) return; collect_types_from_leaf_expr(expr, types, VAR_DECL); } static void collect_types_from_field_decl(const_tree expr, ptrset_t &types) { + location_t loc = DECL_SOURCE_LOCATION(expr); + const bool is_builtin = BUILTINS_LOCATION == loc; + if (is_builtin) return; collect_types_from_leaf_expr(expr, types, FIELD_DECL); } @@ -353,7 +359,6 @@ collect_types_from_expr(const_tree expr, ptrset_t &types) collect_types_from_function_decl(expr, types); break; default: - log("tree_code: %s\n", get_tree_code_name(code)); gcc_unreachable(); break; } @@ -444,6 +449,12 @@ collect_types_from_stmt_call_lhs(gimple *stmt, ptrset_t &types) is_gimple_code(stmt, GIMPLE_CALL); const_tree lhs = gimple_call_lhs(stmt); if (!lhs) return; + + tree fn = gimple_call_fndecl(stmt); + if (!fn) return; + + const_tree decl_name = DECL_NAME(fn); + const char *identifier = decl_name ? IDENTIFIER_POINTER(decl_name) : ""; collect_types_from_expr(lhs, types); } @@ -776,7 +787,6 @@ sanity_check_ptr_xor_complement(ptrset_t &types) const_tree type_com = *j; gcc_assert(type_com); const bool valid_sets = !eq_type_compare(type_ptr, type_com); - log("comparing %s == %s\n", type_to_string(type_ptr).c_str(), type_to_string(type_com).c_str()); gcc_assert(valid_sets); } } |