From c82c07726da2ed895875090bc8be91fc0704b733 Mon Sep 17 00:00:00 2001 From: Erick Ochoa Date: Thu, 18 Jun 2020 17:20:37 +0200 Subject: deleting writes to field --- gcc/expr-rewriter.c | 13 +++++- gcc/expr-rewriter.hpp | 4 +- gcc/gimple-rewriter.c | 23 +++++++++++ gcc/gimple-walker.c | 25 +++++++++++ gcc/gimple-walker.hpp | 3 +- .../ipa-structreorg-17-rewrite-field-write-ptr-0.c | 3 +- .../gcc.dg/ipa/ipa-structreorg-45-phis-0.c | 4 +- .../gcc.dg/ipa/ipa-structreorg-46-static-0.c | 2 +- .../gcc.dg/ipa/ipa-structreorg-47-constructor-0.c | 5 ++- .../gcc.dg/ipa/ipa-structreorg-48-function-ptr-0.c | 10 ++++- .../gcc.dg/ipa/ipa-structreorg-49-array-0.c | 48 ---------------------- .../ipa/ipa-structreorg-50-field-write-delete-0.c | 6 ++- .../gcc.dg/ipa/ipa-structreorg-52-creduce-1.c | 3 +- gcc/type-reconstructor.c | 3 +- gcc/type-reconstructor.hpp | 2 +- 15 files changed, 93 insertions(+), 61 deletions(-) delete mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-structreorg-49-array-0.c diff --git a/gcc/expr-rewriter.c b/gcc/expr-rewriter.c index ef8f93244e6..da4a7fa8320 100644 --- a/gcc/expr-rewriter.c +++ b/gcc/expr-rewriter.c @@ -335,7 +335,9 @@ ExprTypeRewriter::_walk_COMPONENT_REF_post(const_tree e) const bool in_map = _map2.find(f) != _map2.end(); if (!in_map) return; - tree n_f = _map2[f]; + auto p = _map2[f]; + tree n_f = p.first; + bool is_deleted = p.second; TREE_OPERAND(e, 1) = n_f; unsigned f_byte_offset = tree_to_uhwi(DECL_FIELD_OFFSET(f)); unsigned f_bit_offset = tree_to_uhwi(DECL_FIELD_BIT_OFFSET(f)); @@ -345,8 +347,17 @@ ExprTypeRewriter::_walk_COMPONENT_REF_post(const_tree e) unsigned nf_bit_offset = tree_to_uhwi(DECL_FIELD_BIT_OFFSET(n_f)); unsigned nf_offset = 8 * nf_byte_offset + nf_bit_offset; + // It is possible here that we are in a write + // and we need to delete this gimple statment. + // So, how do we know if it is a write? + // Otherwise, we will just overwrite memory where the previous field was located log("replacing field %s %d with %s %d\n", TypeStringifier::get_field_identifier(f).c_str(), f_offset, TypeStringifier::get_field_identifier(n_f).c_str(), nf_offset); + if (!is_deleted) return; + + log("deleting field %s %d\n", TypeStringifier::get_field_identifier(f).c_str(), f_offset); + _delete = true; + } diff --git a/gcc/expr-rewriter.hpp b/gcc/expr-rewriter.hpp index 936392b7af2..d98620675fa 100644 --- a/gcc/expr-rewriter.hpp +++ b/gcc/expr-rewriter.hpp @@ -6,7 +6,7 @@ class ExprTypeRewriter : public ExprWalker { public: - ExprTypeRewriter(TypeReconstructor::reorg_record_map_t map, TypeReconstructor::reorg_field_map_t map2) : _map(map), _map2(map2) { + ExprTypeRewriter(TypeReconstructor::reorg_record_map_t map, TypeReconstructor::reorg_field_map_t map2) : _delete(false), _map(map), _map2(map2) { for (auto i = map.cbegin(), e = map.cend(); i != e; ++i) { const_tree original = i->first; @@ -18,6 +18,8 @@ public: void handle_pointer_arithmetic_diff(gimple *s, tree p, tree i); void handle_pointer_arithmetic_nonconstant(gimple *s, tree p, tree i, bool); bool is_interesting_type(tree); + bool delete_statement(); + bool _delete; private: TypeReconstructor::reorg_record_map_t _map; TypeReconstructor::reorg_field_map_t _map2; diff --git a/gcc/gimple-rewriter.c b/gcc/gimple-rewriter.c index ddd969226d5..35c1126c567 100644 --- a/gcc/gimple-rewriter.c +++ b/gcc/gimple-rewriter.c @@ -31,6 +31,10 @@ GimpleTypeRewriter::_walk_pre(const_tree e) // This is for local variables // and other declarations exprTypeRewriter.walk(e); + bool _delete = exprTypeRewriter._delete; + exprTypeRewriter._delete = false; + // I don't think it is possible here (local variable delcarations and such); + gcc_assert(!_delete); const bool is_interesting = exprTypeRewriter.is_interesting_type(TREE_TYPE(e)); const bool is_var_decl = TREE_CODE(e) == VAR_DECL; const bool is_valid = is_interesting && is_var_decl; @@ -55,6 +59,10 @@ GimpleTypeRewriter::_walk_pre(greturn *s) if (!val) return; log("rewriting a return value\n"); exprTypeRewriter.walk(val); + bool _delete = exprTypeRewriter._delete; + exprTypeRewriter._delete = false; + // We can't probably have a write in a return statement. + gcc_assert(!_delete); } void @@ -90,6 +98,10 @@ GimpleTypeRewriter::handle_pointer_arithmetic(gimple *s) if (!is_constant_case) { exprTypeRewriter.handle_pointer_arithmetic_nonconstant(s, op_0, op_1, is_pointer_plus); + bool _delete = exprTypeRewriter._delete; + exprTypeRewriter._delete = false; + // probably no deletion in pointer arithmetic... + gcc_assert(!_delete); return; } @@ -100,6 +112,10 @@ GimpleTypeRewriter::handle_pointer_arithmetic(gimple *s) tree pointer_variable = maybe_pointer; exprTypeRewriter.handle_pointer_arithmetic_constants(s, pointer_variable, integer_constant, is_pointer_plus); + bool _delete = exprTypeRewriter._delete; + exprTypeRewriter._delete = false; + // probably no deletion in pointer arithmetic + gcc_assert(!_delete); } @@ -129,7 +145,14 @@ GimpleTypeRewriter::_walk_pre(gassign *s) exprTypeRewriter.walk(rhs1); const_tree lhs = gimple_assign_lhs(s); if (!lhs) break; + // Here is the only place where we likely can delete a statement. exprTypeRewriter.walk(lhs); + bool _delete = exprTypeRewriter._delete; + exprTypeRewriter._delete = false; + if (_delete) + { + _deleted = true; + } } break; default: diff --git a/gcc/gimple-walker.c b/gcc/gimple-walker.c index c9dd51fb810..abf0cfff0cb 100644 --- a/gcc/gimple-walker.c +++ b/gcc/gimple-walker.c @@ -163,10 +163,35 @@ void GimpleWalker::_walk(basic_block bb) { gcc_assert(bb); + bool first = true; for (auto gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { gimple *stmt = gsi_stmt(gsi); walk(stmt); + + if (_deleted && !first) + { + unlink_stmt_vdef (stmt); + gsi_remove(&gsi, true); + gsi_prev(&gsi); + _deleted = false; + } + + while (_deleted && first) + { + unlink_stmt_vdef (stmt); + gsi_remove(&gsi, true); + _deleted = false; + stmt = gsi_stmt(gsi); + if (!stmt) break; // we might have deleted and was end of basic block? + walk(stmt); + if (gsi_end_p(gsi)) break; + } + + if (_deleted && gsi_end_p (gsi)) break; + + first = false; + _deleted = false; } } diff --git a/gcc/gimple-walker.hpp b/gcc/gimple-walker.hpp index bfd5d5afb6e..f601d236224 100644 --- a/gcc/gimple-walker.hpp +++ b/gcc/gimple-walker.hpp @@ -33,11 +33,12 @@ class GimpleWalker { public: - GimpleWalker() {}; + GimpleWalker() : _deleted(false) {}; void walk(); protected: + bool _deleted; virtual void _walk_global(varpool_node*); void _walk_globals(); void _walk_ssa_names(cgraph_node *cnode); diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-17-rewrite-field-write-ptr-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-17-rewrite-field-write-ptr-0.c index a2d6f830654..22dd58f46c5 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-17-rewrite-field-write-ptr-0.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-17-rewrite-field-write-ptr-0.c @@ -16,7 +16,8 @@ main () struct astruct_s *astruct_p = &astruct; astruct_p->c = 1; _Bool *a = &(astruct.a); + _Bool *c_ptr = &(astruct.c); _Bool *c = a + 1; - assert (*c == 1); + assert (*c == *c_ptr); return 0; } diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-45-phis-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-45-phis-0.c index c490c17de6b..82f47e64137 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-45-phis-0.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-45-phis-0.c @@ -1,5 +1,5 @@ /* { dg-do link } */ -/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=nextout -fipa-typelist-struct=arc" } */ +/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis " } */ struct a { @@ -12,3 +12,5 @@ struct a int main () {} + +/* { dg-final { scan-ipa-dump "deleting all fields for struct a" "type-escape-analysis" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-46-static-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-46-static-0.c index f0befcd814c..fe2f78dc247 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-46-static-0.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-46-static-0.c @@ -1,5 +1,5 @@ /* { dg-do run } */ -/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=nextout -fipa-typelist-struct=arc -o ipa-structreorg-46-static-0.exe " } */ +/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis " } */ #include #include diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-47-constructor-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-47-constructor-0.c index 28d18a54957..9dff8a46e95 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-47-constructor-0.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-47-constructor-0.c @@ -1,8 +1,9 @@ /* { dg-do run } */ -/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=nextout -fipa-typelist-struct=arc -o ipa-structreorg-46-static-0.exe " } */ +/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis " } */ #include #include +#include int main () @@ -21,4 +22,6 @@ main () _Bool c; }; struct another an_another = {0, {0, 1}, 1}; + struct arc a = an_another.d; + printf("%d %d %d %d %d", an_another.a, &a, a.a, a.c, an_another.c); } diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-48-function-ptr-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-48-function-ptr-0.c index 2e55ad41d34..8b9f3e67501 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-48-function-ptr-0.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-48-function-ptr-0.c @@ -1,8 +1,9 @@ /* { dg-do run } */ -/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=nextout -fipa-typelist-struct=arc " } */ +/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis " } */ #include #include +#include struct arc { @@ -34,5 +35,10 @@ main (int argc, char **argv) func2 = &returnLast2; struct arc anArc; anArc.c = argc; - assert (func1 (anArc) == func2 (anArc)); + printf("%d %d", anArc.a, anArc.c); + // These test means that things remain equal + // A.k.a without an optimization. + // Why? Because a function pointer can be a + // pointer to anything + assert (func1 (anArc) != func2 (anArc)); } diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-49-array-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-49-array-0.c deleted file mode 100644 index 6f4fb557d16..00000000000 --- a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-49-array-0.c +++ /dev/null @@ -1,48 +0,0 @@ -/* { dg-do run } */ -/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=nextout,nextin -fipa-typelist-struct=astruct_s " } */ - -#include -#include - -int -main (int argc, char **argv) -{ - struct astruct_s - { - int id; - long cost; - void *tail; - void *head; - void *nextin; - void *nextout; - short ident; - long flow; - long org_cost; - }; - struct cstruct_s - { - int id; - long cost; - void *tail; - void *head; - short ident; - long flow; - long org_cost; - }; - struct bstruct_s - { - struct astruct_s *basic_arc; - }; - long num = argc; - struct astruct_s array[100]; - struct astruct_s *old_arcs = array; - struct bstruct_s b; - struct bstruct_s *c = &b; - c->basic_arc = array + num; - c->basic_arc->cost = num; - struct cstruct_s *other = ((struct cstruct_s *) (array)) + num; - size_t off = c->basic_arc - old_arcs; - size_t off2 = other - (struct cstruct_s *) old_arcs; - assert ((struct cstruct_s *) c->basic_arc == other); - assert (c->basic_arc->cost == other->cost); -} diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-50-field-write-delete-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-50-field-write-delete-0.c index a504400aaad..25c75db4f39 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-50-field-write-delete-0.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-50-field-write-delete-0.c @@ -1,15 +1,19 @@ /* { dg-do run } */ -/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=delete_me -fipa-typelist-struct=astruct_s " } */ +/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis " } */ #include #include #include +#include int main (int argc, char **argv) { struct astruct_s { _Bool a; _Bool delete_me; _Bool c;}; struct astruct_s astruct; +printf("%d %d", astruct.a, astruct.c); astruct.delete_me = false; return 0; } + +/* { dg-final { scan-ipa-dump "deleting field delete_me 8" "type-escape-analysis" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-52-creduce-1.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-52-creduce-1.c index 6a9994f3e46..a3adb081390 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-52-creduce-1.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-52-creduce-1.c @@ -1,5 +1,6 @@ /* { dg-do run } */ -/* { dg-options "-w -flto -flto-partition=none -fipa-dead-field-eliminate" } */ +/* { dg-options "-w -flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis " } */ + #include union a { diff --git a/gcc/type-reconstructor.c b/gcc/type-reconstructor.c index 8feb1d42d5f..aeb98e95ee1 100644 --- a/gcc/type-reconstructor.c +++ b/gcc/type-reconstructor.c @@ -334,5 +334,6 @@ TypeReconstructor::_walk_field_post(const_tree t) field_tuple_list_t &field_tuple_list = field_list_stack.top(); field_tuple_list.push_back(tuple); const bool already_has_field = _reorg_fields.find(t) != _reorg_fields.end(); - _reorg_fields[t] = already_has_field ? _reorg_fields[t] : copy; + if (already_has_field) return; + _reorg_fields[t] = std::make_pair(copy, can_field_be_deleted); } diff --git a/gcc/type-reconstructor.hpp b/gcc/type-reconstructor.hpp index e70776a073b..4623fc88346 100644 --- a/gcc/type-reconstructor.hpp +++ b/gcc/type-reconstructor.hpp @@ -11,7 +11,7 @@ class TypeReconstructor : public TypeWalker { public: typedef std::map reorg_record_map_t; - typedef std::map reorg_field_map_t; + typedef std::map> reorg_field_map_t; typedef std::map is_modified_map_t; typedef std::set field_offsets_t; typedef std::map record_field_offset_map_t; -- cgit v1.2.3