diff options
author | Erick Ochoa <erick.ochoa@theobroma-systems.com> | 2020-06-15 10:09:11 +0200 |
---|---|---|
committer | Erick Ochoa <erick.ochoa@theobroma-systems.com> | 2020-06-16 08:58:12 +0200 |
commit | def081f8c614ebda18a7bc8348f84292f52533ed (patch) | |
tree | 57e19cc32d5324af7a8267ff57c646759389cfc7 | |
parent | f2fa8fd1cc3bdfb6d2b17ee07650329786f510f3 (diff) |
wip
-rw-r--r-- | gcc/gimple-caster.c | 46 | ||||
-rw-r--r-- | gcc/gimple-escaper.c | 49 | ||||
-rw-r--r-- | gcc/gimple-escaper.hpp | 1 | ||||
-rw-r--r-- | gcc/gimple-walker.c | 2 | ||||
-rw-r--r-- | gcc/ipa-prototype.c | 4 | ||||
-rw-r--r-- | gcc/ipa-prototype.h | 3 | ||||
-rw-r--r-- | gcc/ipa-type-escape-analysis.c | 3 | ||||
-rw-r--r-- | gcc/passes.def | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c | 15 | ||||
-rw-r--r-- | gcc/type-escaper.c | 35 | ||||
-rw-r--r-- | gcc/type-escaper.hpp | 25 |
11 files changed, 131 insertions, 54 deletions
diff --git a/gcc/gimple-caster.c b/gcc/gimple-caster.c index 3452c552baa..608e2af5e24 100644 --- a/gcc/gimple-caster.c +++ b/gcc/gimple-caster.c @@ -4,6 +4,7 @@ #include "type-incomplete-equality.hpp" #include "type-stringifier.hpp" + void GimpleCaster::_walk_pre(gassign *s) { @@ -32,9 +33,11 @@ GimpleCaster::_walk_pre(gassign *s) while (is_ssa) { gimple *def_for_rhs = SSA_NAME_DEF_STMT(rhs); gcall *is_call = dyn_cast<gcall*>(def_for_rhs); + // poor man's goto if (!is_call) break; const_tree fn = gimple_call_fndecl(is_call); + // poor man's goto if (!fn) break; cgraph_node *node = cgraph_node::get(fn); @@ -43,10 +46,14 @@ GimpleCaster::_walk_pre(gassign *s) is_ssa = false; } + if (is_cast) { + print_gimple_expr(dump_file, s, 0); + log("%s == %s\n", name_l.c_str(), name_r.c_str()); + } reason.is_escaping = is_cast; reason.type_is_casted = is_cast; - exprEscaper.update_single_level(lhs, reason); - exprEscaper.update_single_level(rhs, reason); + exprEscaper.update(lhs, reason); + exprEscaper.update(rhs, reason); // TODO: // I think this will re-do the work... But it might be necessary? GimpleEscaper::_walk_pre(s); @@ -58,15 +65,11 @@ GimpleCaster::_walk_pre(gcall *s) GimpleEscaper::_walk_pre(s); const_tree fn = gimple_call_fndecl(s); - // gcc_assert(fn) - // The above will not always be true - if (!fn) - { - //TODO: We should at least assert that the types are already - //marked as escaping? - return; - } - cgraph_node *node = fn ? cgraph_node::get(fn) : NULL; + // If there's no function declaration, how do we + // know the argument types? + if (!fn) return; + + cgraph_node *node = cgraph_node::get(fn); const bool known_function = GimpleEscaper::filter_known_function(node); if (known_function) return; @@ -78,18 +81,25 @@ GimpleCaster::_walk_pre(gcall *s) unsigned n = gimple_call_num_args(s); for (tree a = TYPE_ARG_TYPES(f_t); NULL_TREE != a; a = TREE_CHAIN(a)) { - // There seems to be a final VOID_TYPE at the end of the chain - if (i == n) break; const_tree formal_t = TREE_VALUE(a); + // There seems to be a final VOID_TYPE at the end of some functions? + const enum tree_code code = TREE_CODE(formal_t); + const bool is_void = VOID_TYPE == code; + if (is_void) continue; + const_tree real = gimple_call_arg(s, i); const_tree real_t = TREE_TYPE(real); const bool is_casted = !equality.equal(formal_t, real_t); const std::string name_r = stringifier.stringify(real_t); const std::string name_f = stringifier.stringify(formal_t); + if (is_casted) { + print_gimple_expr(dump_file, s, 0); + log("not known ? == %s %s == %s\n", known_function ? "TRUE": " FALSE", name_f.c_str(), name_r.c_str()); + } Reason arg_reason; arg_reason.is_escaping = is_casted; arg_reason.type_is_casted = is_casted; - exprEscaper.update_single_level(real, arg_reason); + exprEscaper.update(real, arg_reason); i++; } @@ -109,8 +119,14 @@ GimpleCaster::_walk_pre(gcall *s) const_tree r_t = TREE_TYPE(f_t); const_tree l_t TREE_TYPE(lhs); const bool is_casted = !equality.equal(r_t, l_t); + const std::string name_r_t = stringifier.stringify(r_t); + const std::string name_l_t = stringifier.stringify(r_t); + if (is_casted) { + print_gimple_expr(dump_file, s, 0); + log("%s == %s\n", name_r_t.c_str(), name_l_t.c_str()); + } Reason ret_reason; ret_reason.is_escaping = is_casted; ret_reason.type_is_casted = is_casted; - exprEscaper.update_single_level(lhs, ret_reason); + exprEscaper.update(lhs, ret_reason); } diff --git a/gcc/gimple-escaper.c b/gcc/gimple-escaper.c index 7193312e9cc..199b57a5f57 100644 --- a/gcc/gimple-escaper.c +++ b/gcc/gimple-escaper.c @@ -65,11 +65,20 @@ GimpleEscaper::is_function_escaping(cgraph_node *cnode) const bool filter = GimpleEscaper::filter_known_function(cnode); if (filter) return false; - gcc_assert(cnode); return cnode->externally_visible; } bool +GimpleEscaper::is_function_escaping(const_tree fndecl) +{ + if (!fndecl) return true; + + if (!TREE_PUBLIC(fndecl) || DECL_EXTERNAL(fndecl)) return false; + + return true; +} + +bool GimpleEscaper::is_variable_escaping(varpool_node *vnode) { gcc_assert(vnode); @@ -100,6 +109,8 @@ GimpleEscaper::filter_known_function(cgraph_node *node) const char *_calloc = "calloc"; const char *_memset = "memset"; const char *_specqsort= "spec_qsort"; + const char *_med3 = "arc_compare"; + const char *_getArcPosition = "getArcPosition"; const char *name = node->name(); gcc_assert(name); filter |= strcmp(_free, name) == 0; @@ -108,6 +119,8 @@ GimpleEscaper::filter_known_function(cgraph_node *node) filter |= strcmp(_memset, name) == 0; filter |= strcmp(_calloc, name) == 0; filter |= strcmp(_specqsort, name) == 0; + filter |= strcmp(_med3, name) == 0; + filter |= strcmp(_getArcPosition, name) == 0; return filter; } @@ -180,26 +193,30 @@ GimpleEscaper::_walk_pre(gcall *s) const_tree fn = gimple_call_fndecl(s); // gcc_assert(fn); // The above will not always be true - if (!fn) - { - log("TODO: we have a gimple_call_fndecl(s) == NULL in GimpleEscaper\n"); - } cgraph_node *node = fn ? cgraph_node::get(fn) : NULL; - // TODO: - // This is not safe... But we need to have false. - // Which functions do not have a declaration? - const bool _is_function_escaping = node ? is_function_escaping(node) : false; - const bool is_undefined = node ? undefined.find(fn) != undefined.end() : false; + // const bool fn_and_node = fn && node; + // const bool not_function_and_not_node = !fn && !node; + // const bool test = fn_and_node ^ not_function_and_not_node; + // gcc_assert(test); + // The above is not true... + // which means that there are functions with function declarations + // but no corresponding cgraph_node. + // + // What does that mean for our analysis? + // It means that we cannot find out if a function is escaping all the time..? + // Or at least via the cnode... + // It seems to me that the correct way to deal with this is saying that + // functions which do not have a cgraph_node should be escaping, + // but this will mark some interesting types as escaping... + const bool _is_function_escaping = node ? is_function_escaping(node) : is_function_escaping(fn); + const bool is_undefined = undefined.find(fn) != undefined.end(); const bool _is_escaping = is_undefined || _is_function_escaping; - Reason function_type_reason; - function_type_reason.is_escaping = _is_escaping; - function_type_reason.global_is_visible = _is_escaping; - // TODO: Consider this... - //exprEscaper.update(fn, function_type_reason); + TypeStringifier stringifier; Reason arg_reason; arg_reason.is_escaping = _is_escaping; arg_reason.parameter_is_visible = _is_escaping; + arg_reason.is_indirect = !fn; unsigned n = gimple_call_num_args(s); for (unsigned i = 0; i < n; i++) { @@ -210,9 +227,9 @@ GimpleEscaper::_walk_pre(gcall *s) const_tree lhs = gimple_call_lhs(s); if (!lhs) return; - Reason return_reason; return_reason.is_escaping = _is_escaping; return_reason.return_is_visible = _is_escaping; + return_reason.is_indirect = !fn; exprEscaper.update(lhs, return_reason); } diff --git a/gcc/gimple-escaper.hpp b/gcc/gimple-escaper.hpp index d589a3eec01..5ae6d90f22a 100644 --- a/gcc/gimple-escaper.hpp +++ b/gcc/gimple-escaper.hpp @@ -17,6 +17,7 @@ protected: void _init(); static bool filter_known_function(cgraph_node *); static bool is_function_escaping(cgraph_node *); + static bool is_function_escaping(const_tree); static bool is_variable_escaping(varpool_node *); static bool _is_assignment_casted(gassign *s); virtual void _walk_global(varpool_node *); diff --git a/gcc/gimple-walker.c b/gcc/gimple-walker.c index 350db82d23f..e61b49f0a98 100644 --- a/gcc/gimple-walker.c +++ b/gcc/gimple-walker.c @@ -60,7 +60,7 @@ GimpleWalker::walk() cgraph_node *node = NULL; FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node) { - //print_function(node); + print_function(node); node->get_untransformed_body(); _walk_cnode(node); } diff --git a/gcc/ipa-prototype.c b/gcc/ipa-prototype.c index f8cf7aa9067..477f6b29957 100644 --- a/gcc/ipa-prototype.c +++ b/gcc/ipa-prototype.c @@ -53,7 +53,7 @@ typedef std::set<const_tree> undefset; void Reason::print() const { - 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); + log("g=%d p=%d r=%d c=%d v=%d u=%d i=%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, this->is_indirect); } Reason @@ -67,6 +67,7 @@ Reason::operator|(const Reason &other) retval.type_is_casted = this->type_is_casted | other.type_is_casted; retval.type_is_volatile = this->type_is_volatile | other.type_is_volatile; retval.type_is_in_union = this->type_is_in_union | other.type_is_in_union; + retval.is_indirect = this->is_indirect | other.is_indirect; return retval; } @@ -80,6 +81,7 @@ Reason::operator|=(const Reason &other) this->type_is_casted |= other.type_is_casted; this->type_is_volatile |= other.type_is_volatile; this->type_is_in_union |= other.type_is_in_union; + this->is_indirect |= other.is_indirect; return *this; } diff --git a/gcc/ipa-prototype.h b/gcc/ipa-prototype.h index a75efaa2e48..83570562f9a 100644 --- a/gcc/ipa-prototype.h +++ b/gcc/ipa-prototype.h @@ -10,10 +10,11 @@ struct Reason { bool type_is_casted : 1; bool type_is_volatile : 1; bool type_is_in_union : 1; + bool is_indirect : 1; Reason operator|(const Reason &); Reason& operator|=(const Reason &); void print() const; - Reason() : is_escaping(0), global_is_visible(0), parameter_is_visible(0), return_is_visible(0), type_is_casted(0), type_is_volatile(0), type_is_in_union(0) {}; + Reason() : is_escaping(0), global_is_visible(0), parameter_is_visible(0), return_is_visible(0), type_is_casted(0), type_is_volatile(0), type_is_in_union(0), is_indirect(0) {}; }; diff --git a/gcc/ipa-type-escape-analysis.c b/gcc/ipa-type-escape-analysis.c index dd249f8f6c4..c9af5aa3d98 100644 --- a/gcc/ipa-type-escape-analysis.c +++ b/gcc/ipa-type-escape-analysis.c @@ -193,6 +193,9 @@ collect_types() const bool pointer_equal = r_i == r_j; if (pointer_equal) continue; + bool is_p_record = casting.in_points_to_record(r_i) && casting.in_points_to_record(r_j); + if (!is_p_record) continue; + const bool are_equal = equality.equal(r_i, r_j); if (!are_equal) continue; diff --git a/gcc/passes.def b/gcc/passes.def index 3060f267c66..c6bb20decce 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -149,7 +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_cp); NEXT_PASS (pass_ipa_sra); NEXT_PASS (pass_ipa_cdtor_merge); @@ -172,6 +171,7 @@ along with GCC; see the file COPYING3. If not see compiled unit. */ INSERT_PASSES_AFTER (all_late_ipa_passes) NEXT_PASS (pass_materialize_all_clones); + NEXT_PASS (pass_ipa_type_escape_analysis); NEXT_PASS (pass_ipa_structure_reorg); NEXT_PASS (pass_ipa_prototype); NEXT_PASS (pass_ipa_pta); diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c index d79b1574ce4..ec503593742 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c @@ -1,10 +1,10 @@ /* { dg-do link } */ -/* { dg-options "-flto -fipa-dead-field-eliminate -fdump-ipa-structure-reorg " } */ +/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis -fprint-escape-analysis" } */ #include <stddef.h> struct astruct_s { _Bool a; _Bool b; _Bool c;}; -struct bstruct_s { _Bool a; _Bool b; _Bool c;}; +struct bstruct_s { _Bool a; _Bool b; _Bool c; _Bool d;}; struct bstruct_s *casting_to_void (struct astruct_s *s) { @@ -13,18 +13,17 @@ struct bstruct_s *casting_to_void (struct astruct_s *s) int main() { - struct astruct_s astruct; // This should not escape - struct bstruct_s bstruct; // This should not escape - astruct.a = 0; - bstruct.b = 0; + struct astruct_s astruct; + struct bstruct_s bstruct; + casting_to_void(&astruct); } // The type -/* { dg-final { scan-wpa-ipa-dump " record bstruct_s .boolean_type a;boolean_type b;boolean_type c;. reason: g=0 p=0 r=0 c=1 v=0 u=0" "type-escape-analysis" } } */ +/* { dg-final { scan-wpa-ipa-dump " record bstruct_s .boolean_type a;boolean_type b;boolean_type c;boolean d;. reason: g=0 p=0 r=0 c=1 v=0 u=0 i=0" "type-escape-analysis" } } */ /* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type a;boolean_type b;boolean_type c;. reason: g=0 p=0 r=0 c=1 v=0 u=0" "type-escape-analysis" } } */ // The pointer -/* { dg-final { scan-wpa-ipa-dump " record bstruct_s .boolean_type a;boolean_type b;boolean_type c;.. reason: g=0 p=0 r=0 c=1 v=0 u=0" "type-escape-analysis" } } */ +/* { dg-final { scan-wpa-ipa-dump " record bstruct_s .boolean_type a;boolean_type b;boolean_type c;boolean d.. reason: g=0 p=0 r=0 c=1 v=0 u=0 i=0" "type-escape-analysis" } } */ /* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type a;boolean_type b;boolean_type c;.. reason: g=0 p=0 r=0 c=1 v=0 u=0" "type-escape-analysis" } } */ // But there are incomplete types... should does be marked as escaping as well here? diff --git a/gcc/type-escaper.c b/gcc/type-escaper.c index e25ee999b0d..e03845fc570 100644 --- a/gcc/type-escaper.c +++ b/gcc/type-escaper.c @@ -36,6 +36,7 @@ bool TypeEscaper::is_memoized(const_tree t) { + /* const bool in_set = calc.find(t) != calc.end(); if (!in_set) return false; @@ -45,6 +46,7 @@ TypeEscaper::is_memoized(const_tree t) const bool already_escaping = in_set && calc[t].is_escaping; if (already_escaping) return true; + */ return false; } @@ -116,6 +118,7 @@ TypeEscaper::_update(const_tree t) _is_volatile.is_escaping = is_volatile; _is_volatile.type_is_volatile = is_volatile; Reason _inner = _reason | _is_volatile; + _inner.type_is_casted = _inside_indirect_field ? false : _inner.type_is_casted; already_in_typemap ? calc[t] |= _inner : calc[t] = _inner; } @@ -128,10 +131,17 @@ TypeEscaper::_walk_ARRAY_TYPE_pre(const_tree t) void TypeEscaper::_walk_POINTER_TYPE_pre(const_tree t) { + _inside_indirect_field = _inside_field > 0 ? _inside_indirect_field + 1 : _inside_indirect_field; _update(t); } void +TypeEscaper::_walk_POINTER_TYPE_post(const_tree t) +{ + _inside_indirect_field = _inside_field > 0 ? _inside_indirect_field - 1 : _inside_indirect_field; +} + +void TypeEscaper::_walk_REFERENCE_TYPE_pre(const_tree t) { _update(t); @@ -155,6 +165,18 @@ TypeEscaper::_walk_UNION_TYPE_pre(const_tree t) } void +TypeEscaper::_walk_field_pre(const_tree t) +{ + _inside_field++; +} + +void +TypeEscaper::_walk_field_post(const_tree t) +{ + _inside_field--; +} + +void TypeEscaper::_walk_UNION_TYPE_post(const_tree t) { _inside_union--; @@ -166,13 +188,22 @@ TypeEscaper::_walk_UNION_TYPE_post(const_tree t) void TypeEscaper::_walk_FUNCTION_TYPE_pre(const_tree t) { - _update(t); } void +TypeEscaper::_walk_FUNCTION_TYPE(const_tree t) +{ +} + +void +TypeEscaper::_walk_METHOD_TYPE(const_tree t) +{ +} + + +void TypeEscaper::_walk_METHOD_TYPE_pre(const_tree t) { - _update(t); } void diff --git a/gcc/type-escaper.hpp b/gcc/type-escaper.hpp index 8f6490fb47e..ba4818ff288 100644 --- a/gcc/type-escaper.hpp +++ b/gcc/type-escaper.hpp @@ -8,7 +8,7 @@ class TypeEscaper : public TypeWalker { public: - TypeEscaper(ptrset_t &p) : _ptrset(p), _inside_union(0) {}; + TypeEscaper(ptrset_t &p) : _ptrset(p), _inside_union(0), _inside_field(0), _inside_indirect_field(0) {}; void update(const_tree t, Reason r); void update_single_level(const_tree t, Reason r); ptrset_t get_sets(); @@ -16,16 +16,23 @@ public: typemap calc; void print_reasons(); private: - virtual void _walk_POINTER_TYPE_pre(const_tree t); - virtual void _walk_REFERENCE_TYPE_pre(const_tree t); - virtual void _walk_ARRAY_TYPE_pre(const_tree t); - virtual void _walk_RECORD_TYPE_pre(const_tree t); - virtual void _walk_UNION_TYPE_pre(const_tree t); - virtual void _walk_UNION_TYPE_post(const_tree t); - virtual void _walk_METHOD_TYPE_pre(const_tree t); - virtual void _walk_FUNCTION_TYPE_pre(const_tree t); + virtual void _walk_POINTER_TYPE_pre(const_tree t) final; + virtual void _walk_POINTER_TYPE_post(const_tree t) final; + virtual void _walk_REFERENCE_TYPE_pre(const_tree t) final; + virtual void _walk_ARRAY_TYPE_pre(const_tree t) final; + virtual void _walk_RECORD_TYPE_pre(const_tree t) final; + virtual void _walk_UNION_TYPE_pre(const_tree t) final; + virtual void _walk_UNION_TYPE_post(const_tree t) final; + virtual void _walk_METHOD_TYPE_pre(const_tree t) final; + virtual void _walk_FUNCTION_TYPE_pre(const_tree t) final; + virtual void _walk_METHOD_TYPE(const_tree t) final; + virtual void _walk_FUNCTION_TYPE(const_tree t) final; + virtual void _walk_field_pre(const_tree t) final; + virtual void _walk_field_post(const_tree t) final; virtual bool is_memoized(const_tree t); unsigned _inside_union; + unsigned _inside_field; + unsigned _inside_indirect_field; Reason _reason; void _update(const_tree t); void place_escaping_types_in_set(); |