summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErick Ochoa <erick.ochoa@theobroma-systems.com>2020-06-15 10:09:11 +0200
committerErick Ochoa <erick.ochoa@theobroma-systems.com>2020-06-16 08:58:12 +0200
commitdef081f8c614ebda18a7bc8348f84292f52533ed (patch)
tree57e19cc32d5324af7a8267ff57c646759389cfc7
parentf2fa8fd1cc3bdfb6d2b17ee07650329786f510f3 (diff)
wip
-rw-r--r--gcc/gimple-caster.c46
-rw-r--r--gcc/gimple-escaper.c49
-rw-r--r--gcc/gimple-escaper.hpp1
-rw-r--r--gcc/gimple-walker.c2
-rw-r--r--gcc/ipa-prototype.c4
-rw-r--r--gcc/ipa-prototype.h3
-rw-r--r--gcc/ipa-type-escape-analysis.c3
-rw-r--r--gcc/passes.def2
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c15
-rw-r--r--gcc/type-escaper.c35
-rw-r--r--gcc/type-escaper.hpp25
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();