summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErick Ochoa <erick.ochoa@theobroma-systems.com>2020-05-22 14:17:54 +0200
committerErick Ochoa <erick.ochoa@theobroma-systems.com>2020-06-03 16:05:59 +0200
commite1628477901c83e16e778a945268c11bbcfe215b (patch)
treeba144f88cfb33bc469ef973b54145fd4f21a831a
parentf5971bc5694541fe716bafe052f352856dcc379c (diff)
improving escape analysis
-rw-r--r--gcc/collect-types.c46
-rw-r--r--gcc/compare-types.c15
-rw-r--r--gcc/ipa-hello-world.c33
-rw-r--r--gcc/ipa-hello-world.h3
-rw-r--r--gcc/ipa-type-collector.c14
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);
}
}