From 140efef10e83422f31b8773dd0ffbf72d2fb0741 Mon Sep 17 00:00:00 2001 From: Erick Ochoa Date: Mon, 8 Jun 2020 15:09:24 +0200 Subject: Adds ability to find casting between types --- gcc/Makefile.in | 1 + gcc/collect-types.c | 12 ++++ gcc/collect-types.h | 1 + gcc/expr-escaper.hpp | 1 + gcc/gimple-caster.c | 30 ++++++++ gcc/gimple-caster.hpp | 20 ++++++ gcc/gimple-escaper.c | 45 ++++++++++-- gcc/gimple-escaper.hpp | 1 + gcc/gimple-walker.c | 12 ++++ gcc/gimple-walker.hpp | 30 ++++++++ gcc/ipa-str-reorg-dead-field-eliminate.c | 9 +++ gcc/ipa-str-reorg-utils.h | 10 +-- gcc/ipa-structure-reorg.c | 81 +++++++++++----------- gcc/ipa-structure-reorg.h | 22 ++++++ .../gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c | 15 ++-- gcc/type-collector.c | 1 - gcc/type-escaper.c | 23 ++++++ gcc/type-escaper.hpp | 1 + gcc/types-inlines.h | 31 +++++++++ 19 files changed, 280 insertions(+), 66 deletions(-) create mode 100644 gcc/gimple-caster.c create mode 100644 gcc/gimple-caster.hpp diff --git a/gcc/Makefile.in b/gcc/Makefile.in index aae84bf3b2b..74afacd6128 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1416,6 +1416,7 @@ OBJS = \ type-collector.o \ expr-collector.o \ gimple-collector.o \ + gimple-caster.o \ type-escaper.o \ type-structural-equality.o \ type-structural-main-variant.o \ diff --git a/gcc/collect-types.c b/gcc/collect-types.c index b3febdd57d7..f4ad113b56f 100644 --- a/gcc/collect-types.c +++ b/gcc/collect-types.c @@ -72,3 +72,15 @@ points_to_record_sets_s::in_complement(const_tree type) const return seen_before; } +void +points_to_record_sets_s::print_in_points_to_record() const +{ + TypeStringifier stringifier; + for (auto i = this->points_to_record.cbegin(), e = this->points_to_record.cend(); i != e; ++i) + { + const_tree t = *i; + gcc_assert(t); + std::string name = stringifier.stringify(t); + log("collected: %s\n", name.c_str()); + } +} diff --git a/gcc/collect-types.h b/gcc/collect-types.h index 1a6126f6a6d..a2439557332 100644 --- a/gcc/collect-types.h +++ b/gcc/collect-types.h @@ -15,6 +15,7 @@ struct points_to_record_sets_s { bool in_points_to_record(const_tree) const; bool in_complement(const_tree) const; void insert(const_tree, bool); + void print_in_points_to_record() const; }; typedef struct points_to_record_sets_s ptrset_t; diff --git a/gcc/expr-escaper.hpp b/gcc/expr-escaper.hpp index 6498f9e3dd4..bcadbe77782 100644 --- a/gcc/expr-escaper.hpp +++ b/gcc/expr-escaper.hpp @@ -12,6 +12,7 @@ public: ExprEscaper(ptrset_t &types) : typeEscaper(types) {}; ptrset_t get_sets() { return typeEscaper.get_sets(); }; void update(const_tree t, Reason r); + void print_reasons() { typeEscaper.print_reasons(); }; private: Reason _r; virtual void _walk_pre(const_tree e); diff --git a/gcc/gimple-caster.c b/gcc/gimple-caster.c new file mode 100644 index 00000000000..ce96a78d7dc --- /dev/null +++ b/gcc/gimple-caster.c @@ -0,0 +1,30 @@ +#include "gimple-caster.hpp" +#include "gimple-pretty-print.h" + +#include "type-incomplete-equality.hpp" + +void +GimpleCaster::_walk_pre(gassign *s) +{ + print_gimple_stmt(dump_file, s, TDF_NONE); + const enum gimple_rhs_class code = gimple_assign_rhs_class(s); + const bool valid_input = GIMPLE_SINGLE_RHS == code; + if (!valid_input) return; + + // I originally was using gimple_assign_cast_p + // but that proved to be insufficient... + // So we have to use our equality comparison... + TypeIncompleteEquality equality; + const_tree lhs = gimple_assign_lhs(s); + const_tree rhs = gimple_assign_rhs1(s); + gcc_assert(lhs && rhs); + Reason reason {}; + const_tree t_lhs = TREE_TYPE(lhs); + const_tree t_rhs = TREE_TYPE(rhs); + gcc_assert(t_lhs && t_rhs); + const bool is_cast = equality.equal(t_lhs, t_rhs); + reason.is_escaping = is_cast; + reason.type_is_casted = is_cast; + exprEscaper.update(lhs, reason); + exprEscaper.update(rhs, reason); +} diff --git a/gcc/gimple-caster.hpp b/gcc/gimple-caster.hpp new file mode 100644 index 00000000000..2495d537649 --- /dev/null +++ b/gcc/gimple-caster.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "gimple-escaper.hpp" + +/* + * GimpleCaster is intended to walk gimple + * and update a map that will hold information + * on whether a type was casted or not. + */ +class GimpleCaster : public GimpleEscaper +{ +public: + GimpleCaster(ptrset_t &types) : GimpleEscaper(types) {}; +private: + // We don't need this from parent... + virtual void _walk_pre(gcall *s) final {}; + // Find out which structs are casted. + // Technically we could find this out on parent + virtual void _walk_pre(gassign *s); +}; diff --git a/gcc/gimple-escaper.c b/gcc/gimple-escaper.c index 625235e0b8d..4c1cedd7412 100644 --- a/gcc/gimple-escaper.c +++ b/gcc/gimple-escaper.c @@ -92,31 +92,62 @@ GimpleEscaper::_walk_pre(__attribute__((unused)) const_tree t) { // Is any global variable escaping? Reason reason; - //exprEscaper.update(expr, reason); + exprEscaper.update(t, reason); } void GimpleEscaper::_walk_pre(__attribute__((unused)) gassign *s) { Reason reason; - // We really should also walk over the different assigns... - -// Is there a type cast? -//exprEscaper.update(expr, reason); + const enum gimple_rhs_class code = gimple_assign_rhs_class(s); + switch (code) + { + case GIMPLE_TERNARY_RHS: + { + const_tree rhs3 = gimple_assign_rhs3(s); + exprEscaper.update(rhs3, reason); + } + /* fall-through */ + case GIMPLE_BINARY_RHS: + { + const_tree rhs2 = gimple_assign_rhs2(s); + exprEscaper.update(rhs2, reason); + } + /* fall-through */ + case GIMPLE_UNARY_RHS: + case GIMPLE_SINGLE_RHS: + { + const_tree rhs1 = gimple_assign_rhs1(s); + exprEscaper.update(rhs1, reason); + const_tree lhs = gimple_assign_lhs(s); + if (!lhs) break; + exprEscaper.update(lhs, reason); + } + break; + default: + gcc_unreachable(); + break; + } } void GimpleEscaper::_walk_pre(__attribute__((unused)) greturn *s) { Reason reason; - //exprEscaper.update(expr, reason); + const_tree val = gimple_return_retval(s); + if (!val) return; + exprEscaper.update(val, reason); } void GimpleEscaper::_walk_pre(__attribute__((unused)) gcond *s) { Reason reason; - //exprEscaper.update(expr, reason); + const_tree lhs = gimple_cond_lhs(s); + const_tree rhs = gimple_cond_rhs(s); + gcc_assert(lhs && rhs); + exprEscaper.update(lhs, reason); + exprEscaper.update(rhs, reason); } void diff --git a/gcc/gimple-escaper.hpp b/gcc/gimple-escaper.hpp index 45cdd70ab4a..9c439fffe38 100644 --- a/gcc/gimple-escaper.hpp +++ b/gcc/gimple-escaper.hpp @@ -10,6 +10,7 @@ public: GimpleEscaper(ptrset_t &types) : exprEscaper(types) { _init(); }; ExprEscaper exprEscaper; ptrset_t get_sets() { return exprEscaper.get_sets(); }; + void print_reasons() { exprEscaper.print_reasons(); }; private: typedef std::set undefset; undefset undefined; diff --git a/gcc/gimple-walker.c b/gcc/gimple-walker.c index 7a8d9ed2df6..eb15db85a01 100644 --- a/gcc/gimple-walker.c +++ b/gcc/gimple-walker.c @@ -40,6 +40,17 @@ #include "expr-walker.hpp" #include "expr-collector.hpp" #include "gimple-walker.hpp" +#include "tree-cfg.h" + +inline static void +print_function (cgraph_node *cnode) +{ + if (!dump_file) + return; + gcc_assert (cnode); + cnode->get_untransformed_body (); + dump_function_to_file (cnode->decl, dump_file, TDF_NONE); +} void GimpleWalker::walk() @@ -214,3 +225,4 @@ GimpleWalkerFuncDef(gcond *) GimpleWalkerFuncDef(gcall *) GimpleWalkerFuncDef(glabel *) GimpleWalkerFuncDef(gswitch *) + diff --git a/gcc/gimple-walker.hpp b/gcc/gimple-walker.hpp index 219eb7b00b2..cc1ece64f05 100644 --- a/gcc/gimple-walker.hpp +++ b/gcc/gimple-walker.hpp @@ -1,5 +1,35 @@ #pragma once +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple-expr.h" +#include "predict.h" +#include "alloc-pool.h" +#include "tree-pass.h" +#include "cgraph.h" +#include "diagnostic.h" +#include "fold-const.h" +#include "gimple-fold.h" +#include "symbol-summary.h" +#include "tree-vrp.h" +#include "ipa-prop.h" +#include "tree-pretty-print.h" +#include "tree-inline.h" +#include "ipa-fnsummary.h" +#include "ipa-utils.h" +#include "tree-ssa-ccp.h" +#include "stringpool.h" +#include "attribs.h" +#include "tree-ssa-alias.h" +#include "tree-ssanames.h" +#include "gimple.h" +#include "cfg.h" +#include "gimple-iterator.h" +#include "gimple-ssa.h" + class GimpleWalker { public: diff --git a/gcc/ipa-str-reorg-dead-field-eliminate.c b/gcc/ipa-str-reorg-dead-field-eliminate.c index 77f9d3141b2..2e192328ad8 100644 --- a/gcc/ipa-str-reorg-dead-field-eliminate.c +++ b/gcc/ipa-str-reorg-dead-field-eliminate.c @@ -52,6 +52,8 @@ along with GCC; see the file COPYING3. If not see #include "ipa-str-reorg-utils.h" #include "ipa-hello-world.h" +#include "gimple-caster.hpp" + #define test_write(M, ...) \ if (dump_file) \ { \ @@ -2765,6 +2767,13 @@ str_reorg_dead_field_eliminate (__attribute__((unused)) Info *info) int str_reorg_dead_field_eliminate_qual (Info *info) { + GimpleCaster caster(info->sets); + caster.walk(); + // sets here now holds the types that + // are casted... + // So, maybe we want to print them? + caster.print_reasons(); + ptrset_t sets = caster.get_sets(); return 0; } int diff --git a/gcc/ipa-str-reorg-utils.h b/gcc/ipa-str-reorg-utils.h index 1465db03d31..98b81acb565 100644 --- a/gcc/ipa-str-reorg-utils.h +++ b/gcc/ipa-str-reorg-utils.h @@ -33,15 +33,7 @@ const char* get_field_name (const_tree type); #include -inline void -log (const char * const format, ...) -{ - if (!dump_file) return; +#include "types-inlines.h" - va_list args; - va_start(args, format); - vfprintf(dump_file, format, args); - va_end(args); -} #endif diff --git a/gcc/ipa-structure-reorg.c b/gcc/ipa-structure-reorg.c index 5df74ba139e..58e7578a8c8 100644 --- a/gcc/ipa-structure-reorg.c +++ b/gcc/ipa-structure-reorg.c @@ -90,7 +90,6 @@ static void print_program ( FILE *, int); static void print_function ( FILE *, int, function *); static ReorgType_t *get_reorgtype( gimple *stmt, Info *, int); static int num_reorgtypes( gimple *, Info *); -static bool points_to_escape_analysis( Info *); static bool uses_field_of_reorgtypes( gimple *, Info *); //-- debugging only -- @@ -121,35 +120,25 @@ ipa_structure_reorg ( void) // Why not make this a class and avoid having all these parameters // to initialize? // Also, all functions should be references and not pointers... - Info info = { &Reorg_Type, - &Saved_Reorg_Type, - &Prog_Decl, - &StructTypes, - 0, - 0.0, - NULL, - false, - false, - false, - false, - false, - false, - false}; + Info info(&Reorg_Type, &Saved_Reorg_Type, &Prog_Decl, &StructTypes); setup_debug_flags ( &info); if ( !reorg_analysis ( &info) ) { - gcc_unreachable(); return true; } - if ( reorg_qualification ( &info) ) + bool qualified = reorg_qualification(&info); + if ( qualified ) { - #if USE_NEW_INTERFACE +#if USE_NEW_INTERFACE if ( flag_ipa_structure_reorg || flag_ipa_dead_field_eliminate ) { + log("before str_reorg_dead_field_eliminate_qual \n"); str_reorg_dead_field_eliminate_qual ( &info); + // Because I just want to do this now... + return true; } if ( flag_ipa_structure_reorg || flag_ipa_field_reorder ) { @@ -187,6 +176,7 @@ ipa_structure_reorg ( void) // Also, if they change the shape of a type the must create my // type and update the ReorgTypes to reflect this. + log("We are using the old interface...\n"); if ( flag_ipa_structure_reorg || flag_ipa_dead_field_eliminate ) { str_reorg_dead_field_eliminate ( &info); } @@ -262,8 +252,8 @@ reorg_analysis ( Info *info) ptrset_t types = collector.get_pointer_set(); GimpleEscaper gimpleEscaper(types); gimpleEscaper.walk(); - types = gimpleEscaper.get_sets(); - gcc_unreachable(); + info->sets = gimpleEscaper.get_sets(); + info->sets.print_in_points_to_record(); return true; } struct cgraph_node *node; @@ -866,24 +856,49 @@ reorg_qualification ( Info *info) // TBD // This only does a generic legality qualification and each // subpass does its own performance qualification. - return reorg_legality( info); + log("before reorg_leaglity...\n"); + unsigned int retval = reorg_legality( info); + log("after reorg_leaglity...\n"); + return retval; } // Return false if nothing qualified bool reorg_legality( Info *info) { - // NOTE, the following line does nothing unless - // we actually do our own points-to analysis - if( !points_to_escape_analysis( info) ) return false; - - return transformation_legality( info); + log("before transformation leagality...\n"); + bool retval = transformation_legality( info); + log("after transformation leagality...\n"); + return retval; +} + +bool +Info::is_non_escaping_set_empty() +{ + log("before non escaping empty...\n"); + bool retval = this->sets.non_escaping.empty(); + log("after non escaping empty...%s \n", retval ? "t" : "f"); + return retval; } // Return false if nothing qualified +// TODO: +// What exactly is the difference between legality and +// non_escaping? bool transformation_legality ( Info *info) { + //TODO: Gary, for my purposes, I need to start running the + // code related to dead field eliminate. So, I'll add this bit + const bool run_escape_analysis = flag_ipa_dead_field_eliminate && !flag_ipa_instance_interleave && !flag_ipa_field_reorder; + if (run_escape_analysis) + { + log("before empty...\n"); + bool retval = !info->is_non_escaping_set_empty(); + log("after empty...\n"); + return retval; + } + cgraph_node* node; FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node) @@ -1799,20 +1814,6 @@ print_type ( FILE *file, tree type) fprintf ( file, "type: %s\n", text); } -// Does there really need to be here? -// I suspect not. Perhaps if needed -// to run our own points-to analysis -// routine.... it would be invoked here. -// So, just to maintain a point to do this -// from, return true. -// Return false if nothing qualified -bool -points_to_escape_analysis( Info *info) -{ - // TBD - return true; -} - bool uses_field_of_reorgtypes( gimple *stmt, Info * info) { diff --git a/gcc/ipa-structure-reorg.h b/gcc/ipa-structure-reorg.h index 3861efa0be0..6864caf27a3 100644 --- a/gcc/ipa-structure-reorg.h +++ b/gcc/ipa-structure-reorg.h @@ -154,6 +154,7 @@ struct Info { std::map *struct_types; // desing bug fix // ptrset_t holds types which point to records // and types which escape + ptrset_t sets; int num_deleted; double total_cache_accesses; FILE *reorg_dump_file; @@ -165,12 +166,33 @@ struct Info { bool show_new_BBs; bool show_transforms; bool show_bounds; + bool is_non_escaping_set_empty(); + + Info (std::vector *v1, + std::vector *v2, + std::vector *v3, + std::map *v4) + : reorg_type(v1) + , saved_reorg_type(v2) + , prog_decl(v3) + , struct_types(v4) + , num_deleted(0) + , total_cache_accesses(0) + , reorg_dump_file(NULL) + , show_all_reorg_cands(false) + , show_all_reorg_cands_in_detail(false) + , show_prog_decls(false) + , show_new_BBs(false) + , show_transforms(false) + , show_bounds(false) + {}; }; // This will perform a function on the supplied // reorg type. It's primarily to support debugging. typedef void (*ReorgFn)( Info *, ReorgType_t *); +#define USE_NEW_INTERFACE 1 #if USE_NEW_INTERFACE extern int str_reorg_dead_field_eliminate_qual ( Info *); extern int str_reorg_dead_field_eliminate_trans ( Info *); 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 5ef153eb5f9..596f220a72c 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,26 +1,23 @@ /* { dg-do link } */ -/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */ +/* { dg-options "-flto -fipa-dead-field-eliminate -fdump-ipa-structure-reorg " } */ #include struct astruct_s { _Bool a; _Bool b; _Bool c;}; -struct astruct_s astruct; // This should not escape struct bstruct_s { _Bool a; _Bool b; _Bool c;}; -struct bstruct_s bstruct; // This should not escape -void casting_to_void (struct astruct_s *s) +struct bstruct_s *casting_to_void (struct astruct_s *s) { - void *nullify_non_escape = s; + return (struct bstruct_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; } -/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "type-escape-analysis" } } */ -/* { dg-final { scan-wpa-ipa-dump "type astruct_s\\\* is escaping true" "type-escape-analysis" } } */ -/* { dg-final { scan-wpa-ipa-dump "collected,bstruct_s" "type-escape-analysis" } } */ -/* { dg-final { scan-wpa-ipa-dump "type bstruct_s is escaping false" "type-escape-analysis" } } */ +/* { dg-final { scan-wpa-ipa-dump "record" "structure-reorg" } } */ diff --git a/gcc/type-collector.c b/gcc/type-collector.c index a199087ce56..e5bccb0a34a 100644 --- a/gcc/type-collector.c +++ b/gcc/type-collector.c @@ -44,7 +44,6 @@ TypeCollector::collect(const_tree t) { TypeStringifier stringifier; std::string in_name = stringifier.stringify(t); - log("in %s size = %d\n", in_name.c_str(), ptr.size()); gcc_unreachable(); } walk(t); diff --git a/gcc/type-escaper.c b/gcc/type-escaper.c index 977a8af795c..466f13a77cc 100644 --- a/gcc/type-escaper.c +++ b/gcc/type-escaper.c @@ -31,6 +31,7 @@ #include "types-inlines.h" #include "type-escaper.hpp" +#include "type-stringifier.hpp" bool TypeEscaper::is_memoized(const_tree t) @@ -65,6 +66,7 @@ TypeEscaper::get_sets() void TypeEscaper::place_escaping_types_in_set() { + TypeStringifier stringifier; for (auto i = calc.cbegin(), e = calc.cend(); i != e; ++i) { const_tree type = i->first; @@ -78,6 +80,7 @@ TypeEscaper::place_escaping_types_in_set() if (!_ptrset.in_points_to_record(type)) continue; const Reason reason = i->second; + std::string name = stringifier.stringify(type); reason.is_escaping ? _ptrset.escaping.insert(type) : _ptrset.non_escaping.insert(type); } } @@ -154,3 +157,23 @@ TypeEscaper::_walk_METHOD_TYPE_pre(const_tree t) { _update(t); } + +void +TypeEscaper::print_reasons() +{ + TypeStringifier stringifier; + for (auto i = calc.cbegin(), e = calc.cend(); i != e; ++i) + { + const_tree t = i->first; + std::string name = stringifier.stringify(t); + const bool in_universe = _ptrset.in_universe(t); + if (!in_universe) continue; + + Reason r = i->second; + const bool is_escaping = r.is_escaping; + if (!is_escaping) continue; + + log("%s reason: ", name.c_str()); + r.print(); + } +} diff --git a/gcc/type-escaper.hpp b/gcc/type-escaper.hpp index 3bda74aa297..e4025165237 100644 --- a/gcc/type-escaper.hpp +++ b/gcc/type-escaper.hpp @@ -13,6 +13,7 @@ public: ptrset_t get_sets(); ptrset_t &_ptrset; typemap calc; + void print_reasons(); private: virtual void _walk_POINTER_TYPE_pre(const_tree t); virtual void _walk_REFERENCE_TYPE_pre(const_tree t); diff --git a/gcc/types-inlines.h b/gcc/types-inlines.h index ef2629afeec..60666c3ce26 100644 --- a/gcc/types-inlines.h +++ b/gcc/types-inlines.h @@ -1,5 +1,36 @@ #pragma once +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple-expr.h" +#include "predict.h" +#include "alloc-pool.h" +#include "tree-pass.h" +#include "cgraph.h" +#include "diagnostic.h" +#include "fold-const.h" +#include "gimple-fold.h" +#include "symbol-summary.h" +#include "tree-vrp.h" +#include "ipa-prop.h" +#include "tree-pretty-print.h" +#include "tree-inline.h" +#include "ipa-fnsummary.h" +#include "ipa-utils.h" +#include "tree-ssa-ccp.h" +#include "stringpool.h" +#include "attribs.h" +#include "tree-ssa-alias.h" +#include "tree-ssanames.h" +#include "gimple.h" +#include "cfg.h" // needed for gimple-iterator.h +#include "gimple-iterator.h" +#include "gimple-ssa.h" +#include +#include inline void -- cgit v1.2.3