diff options
author | Gary Oblock <gary@amperecomputing.com> | 2020-10-09 21:29:21 -0700 |
---|---|---|
committer | Gary Oblock <gary@amperecomputing.com> | 2020-10-09 21:29:21 -0700 |
commit | dd65938d74e9c97246013ff06040d9dd3904d46b (patch) | |
tree | 9c6fd05788481d99dbfa3db4c61fe6dd6ece70be | |
parent | 30ba851880f2a6fd9e082d628199ed3a8ac95a62 (diff) |
The changes fro v1. They were to performance qualification
and allowed it to qualify the node structure for transformation.
-rw-r--r-- | gcc/ipa-str-reorg-instance-interleave.c | 1375 | ||||
-rw-r--r-- | gcc/ipa-structure-reorg.c | 597 | ||||
-rw-r--r-- | gcc/ipa-structure-reorg.h | 22 |
3 files changed, 1551 insertions, 443 deletions
diff --git a/gcc/ipa-str-reorg-instance-interleave.c b/gcc/ipa-str-reorg-instance-interleave.c index 1d0213f1427..7073c9fc1d2 100644 --- a/gcc/ipa-str-reorg-instance-interleave.c +++ b/gcc/ipa-str-reorg-instance-interleave.c @@ -19,21 +19,24 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ +#include <vector> +#include <map> +#include <set> +#include <list> +#include <algorithm> #include "config.h" #include "system.h" #include "coretypes.h" #include "backend.h" #include "tree.h" #include "tree-ssa.h" +#include "tree-ssa-loop-ivopts.h" #include "tree-dfa.h" #include "gimple.h" #include "tree-pass.h" #include "cgraph.h" #include "gimple-iterator.h" #include "pretty-print.h" -#include <vector> -#include <map> -#include <set> #include "ipa-structure-reorg.h" #include "dumpfile.h" #include "tree-pretty-print.h" @@ -49,13 +52,26 @@ along with GCC; see the file COPYING3. If not see #include "cfgloop.h" #include "wide-int.h" +typedef struct acc_base_info acc_base_info_t; +typedef struct acc_info acc_info_t; +typedef struct varInfo varInfo_t; + static void wrangle_ssa_type( tree, Info_t*); //static bool print_internals (gimple *, void *); static void str_reorg_instance_interleave_qual_part ( Info *); static void str_reorg_instance_interleave_type_part ( Info *); static void header ( bool); +static void print_var_infos ( FILE *, std::vector<varInfo_t> &); +static void compress_acc_infos ( std::vector <acc_info_t>); +static void print_acc_info ( FILE *, acc_info_t *); +static void print_acc_infos ( FILE *, std::vector <acc_info_t>); +static bool acc_lt ( const acc_info_t&, const acc_info_t&); +static bool acc_eq ( const acc_info_t&, const acc_info_t&); +static bool all_but_field_eq ( const acc_info_t&, const acc_info_t&); static double cut_off_eq_single_pool( double); static double alignment_effect( unsigned HOST_WIDE_INT); +static void tell_me_about_ssa_name ( tree, int); +static void analyze_access ( tree , acc_info_t *); static void create_new_types ( Info_t *); static void create_a_new_type ( Info_t *, tree); static unsigned int reorg_perf_qual ( Info *); @@ -93,10 +109,10 @@ static basic_block make_bb ( char *, basic_block); */ // These are dummy values tha alway result the reorganization -#define SINGLE_POOL_RAW_SKIP_IT 0.0 -#define SINGLE_POOL_RAW_DO_IT_ALWAYS 0.0 -#define SINGLE_POOL_ABS_SKIP_IT 0.0 -#define SINGLE_POOL_ABS_DO_IT_ALWAYS 0.0 +#define SINGLE_POOL_RAW_SKIP_IT 0.05 +#define SINGLE_POOL_RAW_DO_IT_ALWAYS 0.90 +#define SINGLE_POOL_ABS_SKIP_IT 0.02 +#define SINGLE_POOL_ABS_DO_IT_ALWAYS 0.10 int str_reorg_instance_interleave_qual ( Info *info) @@ -105,6 +121,7 @@ str_reorg_instance_interleave_qual ( Info *info) // str_reorg_instance_interleave_qual_part ( info); + //if ( BYPASS_TRANSFORM ) return 0; // this modifiies the qualified types. // str_reorg_instance_interleave_type_part ( info); @@ -114,14 +131,21 @@ str_reorg_instance_interleave_qual ( Info *info) int str_reorg_instance_interleave_trans ( Info *info) { + if ( BYPASS_TRANSFORM ) + { + + fprintf ( stderr, "Bypassing str_reorg_instance_interleave_trans for experiment\n"); + return 0; + } + if ( info->show_all_reorg_cands ) { fprintf ( info->reorg_dump_file, "Start of str_reorg_instance_interleave_trans:\n"); print_program ( info->reorg_dump_file, PRINT_FORMAT, 4, info); } - DEBUG ("INTERNALS PRINT\n"); - DEBUG_F (apply_to_all_gimple, print_internals, true, (void *)info); + //DEBUG ("INTERNALS PRINT\n"); + //DEBUG_F (apply_to_all_gimple, print_internals, true, (void *)info); struct cgraph_node *node; FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node) { @@ -245,7 +269,7 @@ str_reorg_instance_interleave_trans ( Info *info) DEBUG_L("ReorgT_ElemAssign: "); DEBUG_F( print_gimple_stmt, stderr, stmt, 0); - INDENT(2); + //INDENT(2); // Needed for helloworld tree lhs = gimple_assign_lhs( stmt); tree rhs = gimple_assign_rhs1( stmt); @@ -255,7 +279,7 @@ str_reorg_instance_interleave_trans ( Info *info) tree ro_side = ro_on_left ? lhs : rhs; tree nonro_side = ro_on_left ? rhs : lhs; - switch ( recognize_op ( ro_side, info) ) // "a->f" + switch ( recognize_op ( ro_side, true, info) ) // "a->f" { case ReorgOpT_Indirect: { @@ -427,14 +451,14 @@ str_reorg_instance_interleave_trans ( Info *info) } // end recognize_op ( rhs, info) switch - INDENT(-2); + //INDENT(-2); } // end ReorgT_ElemAssign case break; case ReorgT_If_Null: case ReorgT_If_NotNull: { - DEBUG_L("ReorgT_If_(Not)Null: "); - DEBUG_F( print_gimple_stmt, stderr, stmt, 0); + //DEBUG_L("ReorgT_If_(Not)Null: "); + //DEBUG_F( print_gimple_stmt, stderr, stmt, 0); /* gimple_cond_set_rhs( stmt, TYPE_MAX_VALUE( pointer_sized_int_node)); @@ -449,14 +473,14 @@ str_reorg_instance_interleave_trans ( Info *info) //tree max = TYPE_MAX_VALUE ( TREE_TYPE ( ri->pointer_rep)); tree max = TYPE_MAX_VALUE ( ri->pointer_rep); - DEBUG_L("max: "); - DEBUG_F(print_generic_expr, stderr, max, (dump_flags_t)0); - DEBUG("\n"); + //DEBUG_L("max: "); + //DEBUG_F(print_generic_expr, stderr, max, (dump_flags_t)0); + //DEBUG("\n"); gimple_cond_set_rhs( cond_stmt, max); - DEBUG_L("after: "); - DEBUG_F( print_gimple_stmt, stderr, stmt, 0); + //DEBUG_L("after: "); + //DEBUG_F( print_gimple_stmt, stderr, stmt, 0); } break; case ReorgT_IfPtrEQ: @@ -465,13 +489,13 @@ str_reorg_instance_interleave_trans ( Info *info) case ReorgT_IfPtrGT: case ReorgT_IfPtrLE: case ReorgT_IfPtrGE: - DEBUG_L("ReorgT_IfPtr*\n"); + //DEBUG_L("ReorgT_IfPtr*\n"); // Not needed for single pool. TBD test this break; case ReorgT_PtrPlusInt: // "a = b + i" { - DEBUG_L("ReorgT_PtrPlusInt: "); - DEBUG_F( print_gimple_stmt, stderr, stmt, 0); + //DEBUG_L("ReorgT_PtrPlusInt: "); + //DEBUG_F( print_gimple_stmt, stderr, stmt, 0); // Needed for hellowotrld // Does the type of stmt need to be adjusted? I assume so. @@ -526,14 +550,14 @@ str_reorg_instance_interleave_trans ( Info *info) gsi_remove ( &gsi, true); - DEBUG_L(""); - DEBUG_F( print_gimple_stmt, stderr, gPPI_rhs2_cast, 0); - DEBUG_L(""); - DEBUG_F( print_gimple_stmt, stderr, gPPI_adj, 0); - DEBUG_L(""); - DEBUG_F( print_gimple_stmt, stderr, gPPI, 0); - DEBUG_L(""); - DEBUG_F( print_gimple_stmt, stderr, gPPI_cast, 0); + //DEBUG_L(""); + //DEBUG_F( print_gimple_stmt, stderr, gPPI_rhs2_cast, 0); + //DEBUG_L(""); + //DEBUG_F( print_gimple_stmt, stderr, gPPI_adj, 0); + //DEBUG_L(""); + //DEBUG_F( print_gimple_stmt, stderr, gPPI, 0); + //DEBUG_L(""); + //DEBUG_F( print_gimple_stmt, stderr, gPPI_cast, 0); } break; case ReorgT_Ptr2Zero: // "a = 0" @@ -587,14 +611,14 @@ str_reorg_instance_interleave_trans ( Info *info) gsi_remove ( &gsi, true); - DEBUG_L(""); - DEBUG_F( print_gimple_stmt, stderr, gPD_rhs1_cast, 0); - DEBUG_L(""); - DEBUG_F( print_gimple_stmt, stderr, gPD_rhs2_cast, 0); - DEBUG_L(""); - DEBUG_F( print_gimple_stmt, stderr, gPD, 0); - DEBUG_L(""); - DEBUG_F( print_gimple_stmt, stderr, gPD_cast, 0); + //DEBUG_L(""); + //DEBUG_F( print_gimple_stmt, stderr, gPD_rhs1_cast, 0); + //DEBUG_L(""); + //DEBUG_F( print_gimple_stmt, stderr, gPD_rhs2_cast, 0); + //DEBUG_L(""); + //DEBUG_F( print_gimple_stmt, stderr, gPD, 0); + //DEBUG_L(""); + //DEBUG_F( print_gimple_stmt, stderr, gPD_cast, 0); } break; case ReorgT_Adr2Ptr: // "a = &x[i]" @@ -616,7 +640,7 @@ str_reorg_instance_interleave_trans ( Info *info) break; case ReorgT_PtrNull: // "x = a == 0" case ReorgT_PtrNotNull: // "x = a != 0" - DEBUG_L("ReorgT_Ptr(Not)Null\n");\ + DEBUG_L("ReorgT_Ptr(Not)Null\n"); \ // TBD /* gimple_set_op( stmt, 2, @@ -635,7 +659,7 @@ str_reorg_instance_interleave_trans ( Info *info) case ReorgT_Malloc: { DEBUG_L("Transform ReorgT_Malloc\n"); - INDENT(2); + //INDENT(2); // We need to use the user malloc function // declaration rather than the builtin!!! @@ -1082,7 +1106,7 @@ str_reorg_instance_interleave_trans ( Info *info) //DEBUG_L("End of malloc:\n"); //DEBUG_F( print_program, PRINT_FORMAT, stderr, 4); } - INDENT(-2); + //INDENT(-2); break; case ReorgT_Calloc: // TBD @@ -1301,8 +1325,8 @@ str_reorg_instance_interleave_trans ( Info *info) // transform any constant zero into it's new repersentation. // OR MAYBE... use FOR_EACH_PHI_ARG for the iterator... - DEBUG_L("Phis with constant operands:\n"); - INDENT(4); + //DEBUG_L("Phis with constant operands:\n"); + //INDENT(4); gphi_iterator pi; for ( pi = gsi_start_phis (bb); !gsi_end_p (pi); gsi_next (&pi)) { @@ -1319,30 +1343,30 @@ str_reorg_instance_interleave_trans ( Info *info) for (int i = 0; i < gimple_phi_num_args (phi); i++) { tree *arg = gimple_phi_arg_def_ptr (phi, i); - DEBUG_A("arg[%d] = ",i); - DEBUG_F(flexible_print, stderr, *arg, 1, (dump_flags_t)0); + //DEBUG_A("arg[%d] = ",i); + //DEBUG_F(flexible_print, stderr, *arg, 1, (dump_flags_t)0); bool int_cst = TREE_CODE ( *arg) == INTEGER_CST; - DEBUG_A("is %sinteger constant\n", int_cst ? "" : "not "); + //DEBUG_A("is %sinteger constant\n", int_cst ? "" : "not "); if ( int_cst && integer_zerop ( *arg) ) { *arg = TYPE_MAX_VALUE ( ri->pointer_rep); - DEBUG_L("arg after = "); - DEBUG_F(flexible_print, stderr, *arg, 1, (dump_flags_t)0); + //DEBUG_L("arg after = "); + //DEBUG_F(flexible_print, stderr, *arg, 1, (dump_flags_t)0); } } } } - INDENT(-4); + //INDENT(-4); } pop_cfun (); } - DEBUG_L("after bulk of transformations\n"); + //DEBUG_L("after bulk of transformations\n"); - DEBUG_F( print_program, info->reorg_dump_file, PRINT_FORMAT, 4, info); + //DEBUG_F( print_program, info->reorg_dump_file, PRINT_FORMAT, 4, info); - DEBUG ("INTERNALS PRINT\n"); - DEBUG_F (apply_to_all_gimple, print_internals, true, (void *)info); + //DEBUG ("INTERNALS PRINT\n"); + //DEBUG_F (apply_to_all_gimple, print_internals, true, (void *)info); // A mini-pass to fixup dangling SSA temps. @@ -1353,7 +1377,7 @@ str_reorg_instance_interleave_trans ( Info *info) std::vector <tree> ssa_to_delete; - DEBUG_L("Mini-Pass on Function %s:\n", lang_hooks.decl_printable_name ( func->decl, 2)); + //DEBUG_L("Mini-Pass on Function %s:\n", lang_hooks.decl_printable_name ( func->decl, 2)); //DEBUG_L("\n"); //DEBUG_F( wolf_fence, info); @@ -1385,21 +1409,21 @@ str_reorg_instance_interleave_trans ( Info *info) // of many functions mapping onto one declaration (which I // even doubt is possible in thi case) can't be a problem. - DEBUG_L("Dangling Types for Function Params (default defs).\n"); - INDENT(4); + //DEBUG_L("Dangling Types for Function Params (default defs).\n"); + //INDENT(4); tree parm; for ( parm = DECL_ARGUMENTS ( func->decl); parm; parm = DECL_CHAIN ( parm) ) { - DEBUG_A("param: "); - DEBUG_F( print_generic_decl, stderr, parm, (dump_flags_t)0); - DEBUG("\n"); - INDENT(2); + //DEBUG_A("param: "); + //DEBUG_F( print_generic_decl, stderr, parm, (dump_flags_t)0); + //DEBUG("\n"); + //INDENT(2); tree old_default_def = ssa_default_def ( func, parm); - DEBUG_A("old_default_def: "); - DEBUG_F( print_generic_expr, stderr, old_default_def, (dump_flags_t)0); - DEBUG("\n"); + //DEBUG_A("old_default_def: "); + //DEBUG_F( print_generic_expr, stderr, old_default_def, (dump_flags_t)0); + //DEBUG("\n"); tree new_default_def; // Modify prameter and do the default def stuff @@ -1409,9 +1433,9 @@ str_reorg_instance_interleave_trans ( Info *info) if ( modify_decl_core ( &parm, info) ) { - DEBUG_A("double check new param: "); - DEBUG_F( print_generic_decl, stderr, parm, (dump_flags_t)0); - DEBUG("\n"); + //DEBUG_A("double check new param: "); + //DEBUG_F( print_generic_decl, stderr, parm, (dump_flags_t)0); + //DEBUG("\n"); // New default def here @@ -1438,11 +1462,11 @@ str_reorg_instance_interleave_trans ( Info *info) new_default_def = make_ssa_name_fn ( func, parm, gimple_build_nop ()); set_ssa_default_def ( func, parm, new_default_def); - DEBUG_A("new_default_def: "); - DEBUG_F(print_generic_expr, stderr, new_default_def, (dump_flags_t)0); - DEBUG(", TYPE: "); - DEBUG_F(print_generic_expr, stderr, TREE_TYPE(new_default_def), (dump_flags_t)0); - DEBUG("\n"); + //DEBUG_A("new_default_def: "); + //DEBUG_F(print_generic_expr, stderr, new_default_def, (dump_flags_t)0); + //DEBUG(", TYPE: "); + //DEBUG_F(print_generic_expr, stderr, TREE_TYPE(new_default_def), (dump_flags_t)0); + //DEBUG("\n"); // TBD REMOVE DUPLICATE! // Replace old one (not really totally hence the @@ -1456,8 +1480,8 @@ str_reorg_instance_interleave_trans ( Info *info) // new default def FOR_EACH_IMM_USE_STMT ( stmt, iter, old_default_def) // <== use other form??? Not { - DEBUG_A("before: "); - DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); + //DEBUG_A("before: "); + //DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); use_operand_p use_p; ssa_op_iter ssa_iter; // The F_E_S_U_O macro was blowing up on a phi @@ -1466,14 +1490,14 @@ str_reorg_instance_interleave_trans ( Info *info) { if ( use_p == NULL ) continue; tree use = USE_FROM_PTR (use_p); - DEBUG_A("use to replace: "); - DEBUG_F( print_generic_expr, stderr, use, (dump_flags_t)0); - DEBUG("\n"); + //DEBUG_A("use to replace: "); + //DEBUG_F( print_generic_expr, stderr, use, (dump_flags_t)0); + //DEBUG("\n"); if (use == old_default_def) SET_USE ( use_p, new_default_def); } - DEBUG_A("after: "); - DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); + //DEBUG_A("after: "); + //DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); } // Get rid of the old default def because it confuses // @@ -1482,12 +1506,12 @@ str_reorg_instance_interleave_trans ( Info *info) release_ssa_name_fn ( func, old_default_def); } } - INDENT(-2); + //INDENT(-2); } - INDENT(-4); + //INDENT(-4); - DEBUG_L("Dangling Types for Function Local (default defs).\n"); - INDENT(4); + //DEBUG_L("Dangling Types for Function Local (default defs).\n"); + //INDENT(4); //DEBUG_L("\n"); //DEBUG_F( wolf_fence, info); @@ -1502,9 +1526,9 @@ str_reorg_instance_interleave_trans ( Info *info) tree decl; FOR_EACH_LOCAL_DECL ( func, i, decl) { - DEBUG_A("local: "); - DEBUG_F( print_generic_decl, stderr, decl, (dump_flags_t)0); - DEBUG("\n"); + //DEBUG_A("local: "); + //DEBUG_F( print_generic_decl, stderr, decl, (dump_flags_t)0); + //DEBUG("\n"); tree old_default_def = ssa_default_def ( func, decl); tree new_default_def; @@ -1544,28 +1568,28 @@ str_reorg_instance_interleave_trans ( Info *info) } } } - INDENT(-4); + //INDENT(-4); // Normal ssa name case - DEBUG_L("Dangling Types for Normal SSA Names:\n"); + //DEBUG_L("Dangling Types for Normal SSA Names:\n"); //DEBUG_L("\n"); //DEBUG_F( wolf_fence, info); - INDENT(4); + //INDENT(4); // We use len instead of using func->length() in the for loop test // because new ssa names are created in the loop body and we // shouldn't process them. unsigned int len = SSANAMES ( func)->length (); - DEBUG_L("len = %d\n",len); + //DEBUG_L("len = %d\n",len); for ( unsigned int i = 0; i < len; i++) { - DEBUG_L("SSANAMES(func)[%d]\n",i); + //DEBUG_L("SSANAMES(func)[%d]\n",i); tree ssa_name = (*SSANAMES ( func))[i]; if( ssa_name == NULL ) { - DEBUG_L("Skip, ssa_name == NULL\n"); + //DEBUG_L("Skip, ssa_name == NULL\n"); continue; } @@ -1576,42 +1600,42 @@ str_reorg_instance_interleave_trans ( Info *info) tree type = TREE_TYPE ( ssa_name); tree bottom_type = base_type_of ( type); ReorgType_t *ri = get_reorgtype_info ( bottom_type, info); - DEBUG_L("ssa_name = "); - DEBUG_F(print_generic_expr, stderr, ssa_name, (dump_flags_t)0); - DEBUG(" %s", a_default_def ? "is default_def" : ""); - DEBUG(" %s", no_defining_stmt ? "has no defining stmt" : ""); - DEBUG(" %s", defined_by_nop ? "defined by a nop" : ""); - DEBUG(", type = "); - DEBUG_F(print_generic_expr, stderr, type, (dump_flags_t)0); - DEBUG(", bottom_type = "); - DEBUG_F(print_generic_expr, stderr, bottom_type, (dump_flags_t)0); - DEBUG(", ri = %p\n",ri); + //DEBUG_L("ssa_name = "); + //DEBUG_F(print_generic_expr, stderr, ssa_name, (dump_flags_t)0); + //DEBUG(" %s", a_default_def ? "is default_def" : ""); + //DEBUG(" %s", no_defining_stmt ? "has no defining stmt" : ""); + //DEBUG(" %s", defined_by_nop ? "defined by a nop" : ""); + //DEBUG(", type = "); + //DEBUG_F(print_generic_expr, stderr, type, (dump_flags_t)0); + //DEBUG(", bottom_type = "); + //DEBUG_F(print_generic_expr, stderr, bottom_type, (dump_flags_t)0); + //DEBUG(", ri = %p\n",ri); // If it's not a dangling type we don't care if ( ri == NULL ) { - DEBUG_L("Skip, ri == NULL\n"); + //DEBUG_L("Skip, ri == NULL\n"); continue; } // A default def is processed seperately if ( a_default_def ) { - DEBUG_L("Skip default_def\n"); + //DEBUG_L("Skip default_def\n"); continue; } gcc_assert ( !no_defining_stmt); gcc_assert ( !defined_by_nop); - DEBUG_L("Defining stmt: "); - DEBUG_F ( print_gimple_stmt, stderr, defining_stmt, 0); + //DEBUG_L("Defining stmt: "); + //DEBUG_F ( print_gimple_stmt, stderr, defining_stmt, 0); tree new_type = ri->pointer_rep; tree new_ssa_name = make_temp_ssa_name( new_type, NULL, "dedangled"); - DEBUG_L("new_ssa_name = "); - DEBUG_F(print_generic_expr, stderr, new_ssa_name, (dump_flags_t)0); - DEBUG("\n"); + //DEBUG_L("new_ssa_name = "); + //DEBUG_F(print_generic_expr, stderr, new_ssa_name, (dump_flags_t)0); + //DEBUG("\n"); #if DEBUGGING for ( unsigned int j = 0; j < SSANAMES ( func)->length (); j++) { @@ -1627,8 +1651,8 @@ str_reorg_instance_interleave_trans ( Info *info) imm_use_iterator iter; FOR_EACH_IMM_USE_STMT ( use_stmt, iter, ssa_name) { - DEBUG_L("use_stmt before: "); - DEBUG_F ( print_gimple_stmt, stderr, use_stmt, 0); + //DEBUG_L("use_stmt before: "); + //DEBUG_F ( print_gimple_stmt, stderr, use_stmt, 0); // Deal with the uses use_operand_p use_p; @@ -1637,14 +1661,14 @@ str_reorg_instance_interleave_trans ( Info *info) //FOR_EACH_SSA_USE_OPERAND( use_p, use_stmt, ssa_iter, SSA_OP_USE ) FOR_EACH_PHI_OR_STMT_USE ( use_p, use_stmt, ssa_iter, SSA_OP_USE ) { - DEBUG_L("use_p = %p\n",use_p); + //DEBUG_L("use_p = %p\n",use_p); if ( use_p == NULL ) continue; tree use = USE_FROM_PTR (use_p); if (use == ssa_name) SET_USE ( use_p, new_ssa_name); } - DEBUG_L("use_stmt after: "); - DEBUG_F ( print_gimple_stmt, stderr, use_stmt, 0); + //DEBUG_L("use_stmt after: "); + //DEBUG_F ( print_gimple_stmt, stderr, use_stmt, 0); // Should update_stmt be called here? // It does not seem either harm or help so I'll @@ -1653,12 +1677,12 @@ str_reorg_instance_interleave_trans ( Info *info) } // Modify the LHS too // TBD This code needs to be more general. - DEBUG_L("What is ssa_name? "); - DEBUG_F(flexible_print, stderr, ssa_name, 1, (dump_flags_t)0); + //DEBUG_L("What is ssa_name? "); + //DEBUG_F(flexible_print, stderr, ssa_name, 1, (dump_flags_t)0); gimple *def = SSA_NAME_DEF_STMT ( ssa_name); - DEBUG_L("def: "); - DEBUG_F ( print_gimple_stmt, stderr, def, 0); + //DEBUG_L("def: "); + //DEBUG_F ( print_gimple_stmt, stderr, def, 0); set_lhs_for ( def, new_ssa_name); @@ -1668,7 +1692,7 @@ str_reorg_instance_interleave_trans ( Info *info) release_ssa_name_fn ( func, ssa_name); } - INDENT(-4); + //INDENT(-4); // Might be a bad idea. #if 0 @@ -1681,17 +1705,20 @@ str_reorg_instance_interleave_trans ( Info *info) pop_cfun (); } - DEBUG_L("after mini-passes\n"); + // This used to be off of.. "if ( info->show_all_reorg_cands ) { ..." + // I'm leaning towards deleting this as redundnt. + //DEBUG ( info->reorg_dump_file, + // "\nEnd of str_reorg_instance_interleave_trans (after mini-psasses):\n\n"); + //DEBUG_F ( print_program, info->reorg_dump_file, PRINT_FORMAT, 4, info); - if ( info->show_all_reorg_cands ) - { - fprintf ( info->reorg_dump_file, "End of str_reorg_instance_interleave_trans:\n"); - print_program ( info->reorg_dump_file, PRINT_FORMAT, 4, info); - } - // TBD Should this be a diagnostic or not? - DEBUG ("INTERNALS PRINT\n"); - DEBUG_F (apply_to_all_gimple, print_internals, true, (void *)info); + //DEBUG ("INTERNALS PRINT\n"); + //DEBUG_F (apply_to_all_gimple, print_internals, true, (void *)info); + + // NOTE, spinning through all the functions and recomputing all the + // dominace info here is a really bad idea. + + return 0; } // Note, the following code might be a bit overly simplistic. @@ -1888,32 +1915,64 @@ struct reorg_bb_info { }; typedef struct perf_bb_info perf_bb_info_t; -typedef struct acc_info acc_info_t; -typedef struct var_info var_info_t; -struct var_info { - varpool_node *var; - sbitmap *bits; - double count; +struct acc_base_info { + bool a_def_def; + bool a_decl; + bool a_func; + bool has_induct_var_acc; + bool multi_induct; + bool complicated; + // TBD Note could look at sign of operation for the + // induction. Variables moving forward are different (cache access + // wise) that those moving backward do the sort/compress shouldn't + // lump them together. + tree acc_base; + tree induct_base; + gimple *function; }; -struct acc_info { - varpool_node *v; - int field_num; +struct varInfo { + // Varpool_nodes are a pain to get at so I'll just + // use the first entry in a run of access info enties + // where all of the information but the field is the + // same. + //varpool_node *var; + acc_info_t *rep_access; + // This seems bit map scheme seems tedious and unnecessay. + // just use the fields + // sbitmap *bits; + std::list<tree> fields; + // The count doesn't vary in the simplified scheme + //double count; }; -struct perf_loop_info { - std::vector <var_info_t*> *vari; - class loop *gcc_loop; +struct acc_info { + // trying to get to the varpool seems too hard + // so I'll try for he decl + //varpool_node *v; + tree access; + tree field; // int field_num; + acc_base_info_t base_info; + ReorgType_t *reorg; }; -static void account_for_use( tree, std::vector <acc_info_t> *); +//struct perf_loop_info { +// std::vector <varInfo_t*> *vari; +// class loop *gcc_loop; +//}; + +static void account_for_access( tree, tree, std::vector <acc_info_t> *, Info_t *); static bool is_array_access( tree); static unsigned int reorg_perf_qual ( Info *info) { - DEBUG_L("reorg_perf_qual:\n"); + if ( info->show_perf_qualify ) + { + fprintf ( info->reorg_dump_file, "Doing Performance Qualification\n"); + } + //DEBUG_L("reorg_perf_qual:\n"); #if 1 // TBD use design in doc but mark ReorgTypes // (do_instance_interleave) that qualify instead of deleting them @@ -1926,7 +1985,8 @@ reorg_perf_qual ( Info *info) { (*(info->reorg_type))[i].do_instance_interleave = true; } - #else + #endif + #if 1 // We are doing a quick and dirty version of performance // qualification for testing purposes and possibly the // initial version of for the main branch. @@ -1949,167 +2009,451 @@ reorg_perf_qual ( Info *info) // Perf Analysis struct cgraph_node *node; + FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node) { struct function *func = DECL_STRUCT_FUNCTION ( node->decl); + + if ( info->show_perf_qualify ) + { + fprintf ( info->reorg_dump_file, "Function: "); + print_generic_expr ( info->reorg_dump_file, + TREE_TYPE(TREE_TYPE( func->decl)), + (dump_flags_t)0); + } + // Ulgy GCC idiom with global pointer to current function. // However, the dominace calculations other things need it. push_cfun ( func); + #if 1 if ( dom_info_available_p ( CDI_DOMINATORS) ) { free_dominance_info ( CDI_DOMINATORS); } calculate_dominance_info (CDI_DOMINATORS); - + #endif + + if ( info->show_perf_qualify ) + { + fprintf ( info->reorg_dump_file," Function: %s\n", + lang_hooks.decl_printable_name ( func->decl, 2)); + } + + // TBD - std::vector<perf_loop_info> loop_perf; - loop_perf.reserve ( number_of_loops ( func)); + //std::vector<perf_loop_info> loop_perf; + //loop_perf.reserve ( number_of_loops ( func)); class loop *loop; + bool missing_cases = false; FOR_EACH_LOOP_FN ( func, loop, LI_ONLY_INNERMOST ) { - loop_perf [ loop->num ].vari = new std::vector<var_info_t*>; // ??? - loop_perf [ loop->num ].gcc_loop = loop; + //We don't need these + //loop_perf [ loop->num ].vari = new std::vector<varInfo_t*>; // ??? + //loop_perf [ loop->num ].gcc_loop = loop; + + std::vector<acc_info_t> acc_info; + std::vector<varInfo_t> var_info; + size_t num_bbs = loop->num_nodes; basic_block *bbs = get_loop_body ( loop); - // TBD Stuff here + // For the basic blocks in the the loop for ( unsigned i = 0; i < loop->num_nodes; i++) { basic_block bb = bbs [i]; + //DEBUG_A("BB %i:\n", bb->index); + //INDENT(4); for ( auto gsi = gsi_start_bb ( bb); !gsi_end_p ( gsi); gsi_next ( &gsi) ) { gimple *stmt = gsi_stmt ( gsi); - if ( contains_a_reorgtype ( stmt, info) != NULL ) + //DEBUG_A("examine: "); + //DEBUG_F ( print_gimple_stmt, stderr, stmt, TDF_DETAILS); + //INDENT(4); + + if ( gimple_code ( stmt) == GIMPLE_LABEL || + gimple_code ( stmt) == GIMPLE_SWITCH ) continue; + + unsigned n_ops = gimple_num_ops( stmt); + tree op; + unsigned ith_op; + for ( ith_op = 0; ith_op < n_ops; ith_op++ ) { - DEBUG_A("examine: "); - DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); - INDENT(4); - unsigned n_ops = gimple_num_ops( stmt); - tree op; - unsigned ith_op; - for ( ith_op = 0; i < n_ops; i++ ) + op = gimple_op ( stmt, ith_op); + // It's lieing about the number of operands... so... + if ( op == NULL ) continue; + //DEBUG_A("op[%d]: %p, ", ith_op, op); + //DEBUG_F(flexible_print, stderr, op, 1, (dump_flags_t)0); + ReorgType_t *tri = tree_contains_a_reorgtype ( op, info); + enum ReorgOpTrans optran = recognize_op ( op, false, info); + // TBD This is where we need to remember + // each germane access + const char *s = optrans_to_str( optran); + // Commenting out these 3 debug commands causes a + // regression + //DEBUG_A(", %s\n", s); + if ( tri != NULL ) { - op = gimple_op ( stmt, ith_op); - ReorgType_t *tri = tree_contains_a_reorgtype (op, info); - if ( tri != NULL ) - { - DEBUG_A(""); - DEBUG_F(print_reorg, stderr, 0, tri); - DEBUG(", "); - DEBUG_F(flexible_print, stderr, op, 1, (dump_flags_t)0); - } + //DEBUG(", "); + //DEBUG_F(print_reorg, stderr, 0, tri); + } + else + { + //DEBUG("\n"); + ; + } + switch ( optran) + { + case ReorgOpT_Indirect: + { + // TBD + // Is the var an induction variable for this loop? + // If so find the assocaite varpool_node and push + // it and the field onto var_acc_info; + tree op_var = TREE_OPERAND( op, 0); + tree op_field = TREE_OPERAND( op, 1); + // Since doesn't have an easily exposed mechanism + // for induction variable I'm hand waving here. + if ( !expr_invariant_in_loop_p ( loop, op_var) ) + { + account_for_access ( op_var, op_field, &acc_info, info); + } + } + break; + case ReorgOpT_Array: + { + // TBD + // Is the var an induction variable for this loop? + // If so find the assocaite varpool_node and push + // it and the field onto var_acc_info; + tree op_var = TREE_OPERAND( op, 0); + tree op_field = TREE_OPERAND( op, 1); + // Since doesn't have an easily exposed mechanism + // for induction variable I'm hand waving here. + if ( !expr_invariant_in_loop_p ( loop, op_var) ) + { + account_for_access ( op_var, op_field, &acc_info, info); + } + } + case ReorgOpT_AryDir: + case ReorgOpT_Deref: // ?? + missing_cases = true; } - INDENT(-4); - } + //INDENT(-4); } - }continue; // Testing above here + //INDENT(-4); + } + //DEBUG_L("Dumping acc_info:\n"); + for ( auto aci = acc_info.begin (); aci != acc_info.end (); aci++ ) + { + //DEBUG_A("variable:\n"); + //DEBUG_F( tell_me_about_ssa_name, (*aci).access, debug_indenting + 4); + //DEBUG_A("field: "); + //DEBUG_F( flexible_print, stderr, (*aci).field, 1, (dump_flags_t)0); + } + + //DEBUG_A("before sort: \n"); + //DEBUG_F(print_acc_infos, stderr, acc_info ); + + // Sort and compact the access infos. + stable_sort ( acc_info.begin (), acc_info.end (), acc_lt); + + //DEBUG_A("before compress: \n"); + //DEBUG_F(print_acc_infos, stderr, acc_info ); + + // Sort and compact the access infos. + std::stable_sort ( acc_info.begin (), acc_info.end (), acc_lt); + + compress_acc_infos ( acc_info ); + + //DEBUG_A("after compress: \n"); + //DEBUG_F(print_acc_infos, stderr, acc_info ); + // Obtain loop count by looking at all the block counts. - unsigned max_count = 0; + unsigned loop_count = 0; for ( unsigned i = 0; i < loop->num_nodes; i++) { basic_block bb = bbs [i]; - max_count = MAX( max_count, bb->count.value ()); + loop_count = MAX( loop_count, bb->count.value ()); + } + //DEBUG_L("loop_count = %d, nb_iterations_estimate = %ld\n", + // loop_count, loop->nb_iterations_estimate); + + // Create the variable infos + varInfo_t var_entry; + var_entry.rep_access = &acc_info[0]; + unsigned len = acc_info.size (); + + // If no accesses detected, never for this loop. + if ( len == 0 ) continue; + + if ( len == 1 ) + { + var_entry.fields.push_front ( acc_info[0].field); + } + else + { + unsigned i, j; + for ( i = 0, j = 1; j < len; j++ ) + { + acc_info_t *a_of_i = &acc_info[i]; + acc_info_t *a_of_j = &acc_info[j]; + var_entry.fields.push_front ( a_of_i->field); + if ( !all_but_field_eq ( *a_of_i, *a_of_j ) ) + { + var_info.push_back( var_entry); + var_entry.rep_access = a_of_j; + var_entry.fields.clear (); + a_of_i = a_of_j; + } + } } - DEBUG_L("max_count = %d, nb_iterations_estimate = %ld\n", - max_count, loop->nb_iterations_estimate); + var_info.push_back( var_entry); + + if ( info->show_perf_qualify ) + { + fprintf ( stderr, "%d VarInfos\n", var_info.size ()); + } + //DEBUG_F(print_var_infos, stderr, var_info); + + // + // Model the performance + // + //DEBUG_A("Model The Performance\n"); // Originally this was done per bb but now it has to be per // loop. TBD But perf_bb is per loop so we need something similar // per loop. - std::vector <var_info_t*> *pv = loop_perf [ loop->num].vari; - for ( auto pvi = pv->begin (); pvi != pv->end (); pvi++ ) + for ( auto pvi = var_info.begin (); pvi != var_info.end (); pvi++ ) { // 676 - tree base_type = base_type_of( ( *pvi)->var->decl); - ReorgType_t *ri = get_reorgtype_info ( base_type, info); + //tree base_type = base_type_of( pvi->rep_access.access); + ReorgType_t *ri = pvi->rep_access->reorg; + // Reorg accounting + //DEBUG_L("\n"); + //DEBUG_A("Reorg Accounting\n"); + if( ri != NULL ) { double reorg_nca = 0.0; - int fi; - tree field; - for( field = TYPE_FIELDS ( ri->gcc_type), fi = 0; - field; - field = DECL_CHAIN ( field), fi++ ) // 684 + + //DEBUG_A(" for: "); + //DEBUG_F( flexible_print, stderr, ri->gcc_type, 1, (dump_flags_t)0); + //INDENT(4); + for ( auto fldi = pvi->fields.begin (); fldi != pvi->fields.end (); fldi++ ) { - if ( bitmap_bit_p ( *(*pvi)->bits, fi) ) - { - unsigned HOST_WIDE_INT fld_width = - tree_to_uhwi ( DECL_SIZE ( field)); - reorg_nca += max_count * alignment_effect ( fld_width); - } + unsigned HOST_WIDE_INT fld_width = + tree_to_uhwi ( DECL_SIZE ( *fldi)); + double effect = alignment_effect ( fld_width); + double product = loop_count * effect; + reorg_nca += product; + //DEBUG_A("Add loop_count * effect (%d * %f = %f) to reorg_nca (now %f)\n", + // loop_count, effect, product, reorg_nca); } + //INDENT(-4); ri->instance_interleave.reorg_perf += reorg_nca; - } // 699 - + //DEBUG_A("Add reorg_nca (%f) to reorg_perf (now %e)\n", + // reorg_nca, ri->instance_interleave.reorg_perf); + } // 699 + // regular accounting + //DEBUG_L("\n"); + //DEBUG_A("Regular Accounting\n"); + double regular_nca = 0.0; sbitmap cache_model = sbitmap_alloc(1); - // TBD NOTE, pv steps on the pv above. - std::vector <var_info_t*> *pv2 = loop_perf[ loop->num].vari; - for( auto pv2i = pv2->begin (); pv2i != pv2->end (); pv2i++ ) { // 704 - tree base_type = base_type_of ( (*pv2i)->var->decl); - // create a tiny model of the cache big - // enough for this record. - unsigned HOST_WIDE_INT len = - (( tree_to_uhwi ( DECL_SIZE ( base_type)) - + - param_l1_cache_line_size -1) - / - param_l1_cache_line_size) - + - 1; - cache_model = sbitmap_resize( cache_model, (unsigned) len, 0); - double accum = 0.0; - int nrbo = 0; - for ( auto field_ex = TYPE_FIELDS ( base_type); - field_ex; - field_ex = DECL_CHAIN ( field_ex) ) - { - nrbo++; - unsigned HOST_WIDE_INT base_offset = - tree_to_uhwi ( DECL_FIELD_OFFSET( field_ex)); - // Access accounting - int fi = 0; - for ( auto field = TYPE_FIELDS ( base_type); - field; - field = DECL_CHAIN ( field), fi++) - { - if ( bitmap_bit_p ( *(*pv2i)->bits, fi) ) + + for( auto pv2i = var_info.begin (); pv2i != var_info.end (); pv2i++ ) + { // 704 + tree access = pv2i->rep_access->base_info.acc_base; + tree base_type; // = base_type_of ( access); + if ( pv2i->rep_access->reorg != NULL ) + { + //DEBUG_A("Base type from reorg: "); + base_type = pv2i->rep_access->reorg->gcc_type; + } + else + { + //DEBUG_A("Base type from access: "); + if ( TREE_TYPE ( access ) != NULL ) + { + base_type = base_type_of ( access); + } + else + { + gcc_assert (0); + } + } + //DEBUG_F( flexible_print, stderr, base_type, 1, (dump_flags_t)0); + + bool base_type_isa_decl = DECL_P ( base_type ); + + // create a tiny model of the cache big + // enough for this record. + #if 0 + tree base_type_size = base_type_isa_decl ? + DECL_SIZE ( base_type ) + : + TYPE_SIZE ( base_type); + #else + tree base_type_size; + if ( base_type_isa_decl ) + { + //DEBUG_A("decl\n"); + switch ( TREE_CODE (base_type) ) + { + case VAR_DECL: { - unsigned HOST_WIDE_INT fld_width, fld_offset; - fld_width = tree_to_uhwi ( DECL_SIZE ( field)); - fld_offset = tree_to_uhwi ( DECL_FIELD_OFFSET ( field)); - int chari; - for ( chari = 0; chari < fld_width; chari++ ) - { - int loc = (chari + fld_offset + base_offset) - / - param_l1_cache_line_size; - bitmap_set_bit ( cache_model, loc); - } + //DEBUG_A("VAR_DECL\n"); + base_type_size = TYPE_SIZE ( base_type); + break; } - } - accum += bitmap_count_bits ( cache_model); - bitmap_clear ( cache_model); - } - regular_nca += accum / nrbo; + case FIELD_DECL: + { + //DEBUG_A("VAR_DECL\n"); + base_type_size = TYPE_SIZE ( TREE_TYPE ( base_type)); + break; + } + default: + { + //DEBUG_A("other decl %s\n", code_str(TREE_CODE (base_type))); + gcc_assert(0); + } + } + } + else + { + //DEBUG_A("nondecl %s\n", code_str(TREE_CODE (base_type))); + if ( TREE_CODE ( base_type) == SSA_NAME ) + { + base_type_size = TYPE_SIZE ( TREE_TYPE( base_type)); + } + else + { + base_type_size = TYPE_SIZE ( base_type); + } + } + #endif + + unsigned HOST_WIDE_INT len = + (( tree_to_uhwi ( base_type_size) + + + param_l1_cache_line_size -1) + / + param_l1_cache_line_size) + + + 1; + //DEBUG_L("\n"); + //DEBUG_A("cache len = %d (lines), for: ", len); + //DEBUG_F( flexible_print, stderr, base_type, 0, (dump_flags_t)0); + //DEBUG("%sstruct\n") - } // 739 + // TBD Does this clear the bits??? It needs to. + // Each bit represents a cache line. + cache_model = sbitmap_resize( cache_model, (unsigned) len, 0); + double accum = 0.0; + int nrbo = 0; + tree type = TREE_TYPE ( base_type); + + //bool a_record = type == NULL && TREE_CODE ( type) == RECORD_TYPE; + bool a_record = type != NULL && TREE_CODE ( type) == RECORD_TYPE; + if ( base_type_isa_decl && a_record ) + { + for ( auto field_ex = TYPE_FIELDS ( base_type); + field_ex; + field_ex = DECL_CHAIN ( field_ex) ) + { + nrbo++; + // Looking back on my design I don't have a clue + // why this is here and what it does. Sigh... + unsigned HOST_WIDE_INT base_offset = + tree_to_uhwi ( DECL_FIELD_OFFSET( field_ex)); + //DEBUG_L("\n"); + //DEBUG_A("For field_ex: "); + //DEBUG_F( flexible_print, stderr, field_ex, 0, (dump_flags_t)0); + //DEBUG(", nrbo %d, base_offset %d\n", nrbo, base_offset); + + // Access accounting + + //INDENT(4); + for ( auto fldi = pv2i->fields.begin (); + fldi != pv2i->fields.end (); fldi++ ) + { + tree field = *fldi; + unsigned HOST_WIDE_INT fld_width, fld_offset; + fld_width = tree_to_uhwi ( DECL_SIZE ( field)); + fld_offset = tree_to_uhwi ( DECL_FIELD_OFFSET ( field)); + //DEBUG_A("Field: "); + //DEBUG_F( flexible_print, stderr, field, 0, (dump_flags_t)0); + //DEBUG(", width = %d, offset = %d\n", fld_width, fld_offset); + int chari; + //INDENT(4); + for ( chari = 0; chari < fld_width; chari++ ) + { + int loc = (chari + fld_offset + base_offset) + / + param_l1_cache_line_size; + //DEBUG_A("loc: %d\n", loc); + bitmap_set_bit ( cache_model, loc); + } + //INDENT(-4); + } + //INDENT(-4); + unsigned bcount = bitmap_count_bits ( cache_model); + accum += bcount; + //DEBUG_L("\n"); + //DEBUG_A("Add popcount of cache (%d) to accum (now %f)\n", + // bcount, accum); + bitmap_clear ( cache_model); + } + } + else + { + nrbo = 1; + accum++; + //DEBUG_L("\n"); + //DEBUG_A("nrbo = 1, increment accum to %f\n", accum); + } + #if 1 + double amount = accum / nrbo; + double product = amount * loop_count; + regular_nca += product; + //DEBUG_L("\n"); + //DEBUG_A("Add loop_count*accum/nrbo (%f*%f/%d = %f) to regular_nca (now %e)\n", + // loop_count, accum, nrbo, product, regular_nca); + #else + double amount = accum / nrbo; + regular_nca += amount; + //DEBUG_L("\n"); + //DEBUG_A("Add accum/nrbo (%f/%d = %f) to regular_nca (now %e)\n", + // accum, nrbo, amount, regular_nca); + #endif + } // 739 sbitmap_free ( cache_model); if( ri != NULL ) { ri->instance_interleave.regular_perf += regular_nca; - cache_accesses_noreorg += regular_nca; - } else { - cache_accesses += regular_nca; - } - } // end for each prop_var 748 - - - } // + cache_accesses_noreorg += regular_nca; + //DEBUG_L("\n"); + //DEBUG_A("Add regular_nca (%f) to regular_perf (now %e)", + // regular_nca, ri->instance_interleave.regular_perf); + //DEBUG_A(" and to cache_accesses_noreorg (now %e)\n", + // cache_accesses_noreorg); + } else { + cache_accesses += regular_nca; + } + } // end for prop_var + } // + + if ( info->show_perf_qualify && missing_cases ) + { + fprintf ( info->reorg_dump_file, + " Ignored unimplemented cases when finding accesses.\n"); + } + + free_dominance_info ( CDI_DOMINATORS); pop_cfun (); } @@ -2124,6 +2468,17 @@ reorg_perf_qual ( Info *info) info->total_cache_accesses = total_cache_accesses; + if ( info->show_perf_qualify ) + { + fprintf ( info->reorg_dump_file, "total_cache_accesses: %e\n\n", + total_cache_accesses); + } + + if ( info->show_perf_qualify ) + { + fprintf ( info->reorg_dump_file, + "Decide which reorgTypes fail performance qualification\n"); + } // // Decide which reorgTypes fail performance qualification // @@ -2134,10 +2489,16 @@ reorg_perf_qual ( Info *info) reorgi != reorg_types->end (); reorgi++ ) { double with_opt = reorgi->instance_interleave.reorg_perf; - double wihtout_opt = reorgi->instance_interleave.regular_perf; - double raw_effect = with_opt/wihtout_opt; + double without_opt = reorgi->instance_interleave.regular_perf; + double raw_effect = with_opt/without_opt; double absolute_effect = - (wihtout_opt - with_opt) / total_cache_accesses; + (without_opt - with_opt) / total_cache_accesses; + //DEBUG_A("For "); + //DEBUG_F(flexible_print, stderr, reorgi->gcc_type, 0, (dump_flags_t)0); + //DEBUG(" with_opt: %e, without_opt %e, total_cache_accesses %e\n", + // with_opt, without_opt, total_cache_accesses); + //DEBUG_A(" Raw Effect: %5.4f, Absolute Effect %5.4f\n", + // raw_effect, absolute_effect); // Note, there would need to be a multi-pool case here if // that is every done. @@ -2145,6 +2506,16 @@ reorg_perf_qual ( Info *info) // If the relative effect is small enough don't bother. if ( raw_effect < SINGLE_POOL_RAW_SKIP_IT ) { + if ( info->show_perf_qualify ) + { + fprintf ( info->reorg_dump_file, " Disqualified: "); + flexible_print ( info->reorg_dump_file, reorgi->gcc_type, 0, + (dump_flags_t)0); + fprintf ( info->reorg_dump_file, ": Very small effect:\n"); + fprintf ( info->reorg_dump_file, + " raw_effect %5.4f < SINGLE_POOL_RAW_SKIP_IT %5.4f\n", + raw_effect, SINGLE_POOL_RAW_SKIP_IT); + } reorgi->do_instance_interleave = false; continue; } @@ -2152,16 +2523,51 @@ reorg_perf_qual ( Info *info) // otherwise look at the absolute effect. if ( raw_effect >= SINGLE_POOL_RAW_DO_IT_ALWAYS ) { + + if ( info->show_perf_qualify ) + { + fprintf ( info->reorg_dump_file, " Qualified: "); + flexible_print ( info->reorg_dump_file, reorgi->gcc_type, 0, + (dump_flags_t)0); + fprintf ( info->reorg_dump_file, ": Large raw effect:\n"); + fprintf ( info->reorg_dump_file, + " raw_effect %5.4f >= SINGLE_POOL_RAW_DO_IT_ALWAYS %5.4f\n", + raw_effect, SINGLE_POOL_RAW_DO_IT_ALWAYS); + } + reorgi->do_instance_interleave = true; continue; } if ( absolute_effect < SINGLE_POOL_ABS_SKIP_IT ) { + if ( info->show_perf_qualify ) + { + fprintf ( info->reorg_dump_file, " Disqualified: "); + flexible_print ( info->reorg_dump_file, reorgi->gcc_type, 0, + (dump_flags_t)0); + fprintf ( info->reorg_dump_file, ": Very small absolute effect:\n"); + fprintf ( info->reorg_dump_file, + " absolute_effect %5.4f < SINGLE_POOL_ABS_SKIP_IT %5.4f\n", + absolute_effect, SINGLE_POOL_ABS_SKIP_IT); + } + reorgi->do_instance_interleave = false; continue; } if ( absolute_effect >= SINGLE_POOL_ABS_DO_IT_ALWAYS ) { + + if ( info->show_perf_qualify ) + { + fprintf ( info->reorg_dump_file, " Qualified: "); + flexible_print ( info->reorg_dump_file, reorgi->gcc_type, 0, + (dump_flags_t)0); + fprintf ( info->reorg_dump_file, ": Large absolute effect:\n"); + fprintf ( info->reorg_dump_file, + " absolute_effect %5.4f >= SINGLE_POOL_ABS_DO_IT_ALWAYS %5.4f\n", + absolute_effect, SINGLE_POOL_ABS_DO_IT_ALWAYS); + } + reorgi->do_instance_interleave = true; continue; } @@ -2172,13 +2578,224 @@ reorg_perf_qual ( Info *info) double cut_off = cut_off_eq_single_pool ( absolute_effect); if ( raw_effect < cut_off ) { + + if ( info->show_perf_qualify ) + { + fprintf ( info->reorg_dump_file, " Disqualified: "); + flexible_print ( info->reorg_dump_file, reorgi->gcc_type, 0, + (dump_flags_t)0); + fprintf ( info->reorg_dump_file, ": Failed cut off equations:\n"); + fprintf ( info->reorg_dump_file, + " raw_effect %5.4f < cut_off %5.4f\n", + raw_effect, cut_off); + } + reorgi->do_instance_interleave = false; - } + continue; + } + + if ( info->show_perf_qualify ) + { + fprintf ( info->reorg_dump_file, " Qualified: "); + flexible_print ( info->reorg_dump_file, reorgi->gcc_type, 0, + (dump_flags_t)0); + fprintf ( info->reorg_dump_file, ": Passed cut off equations:\n"); + fprintf ( info->reorg_dump_file, + " raw_effect %5.4f >= cut_off %5.4f\n", + raw_effect, cut_off); + } + } + #endif +} - free_dominance_info ( CDI_DOMINATORS); +static void +print_var_info ( FILE *file, varInfo_t &vinfo) +{ + print_acc_info ( file, vinfo.rep_access ); + for ( auto fi = vinfo.fields.begin (); fi != vinfo.fields.end (); fi++ ) + { + if ( fi != vinfo.fields.begin () ) fprintf ( stderr,", "); + flexible_print ( stderr, *fi, 0, (dump_flags_t)0); + } + fprintf ( stderr,"\n"); +} - #endif +static void +print_var_infos ( FILE *file, std::vector<varInfo_t> &vinfo) +{ + fprintf( stderr, "print_var_infos:\n"); + for ( auto vi = vinfo.begin (); vi != vinfo.end (); vi++ ) + { + print_var_info ( file, *vi); + } +} + +static void +compress_acc_infos ( std::vector <acc_info_t> ainfo ) +{ + unsigned len = ainfo.size (); + //DEBUG_L("compress_acc_infos: len in %d, ",len); + if ( len <= 1 ) return; + unsigned i, j; + for ( i = j = 1; j < len; j++ ) + { + ainfo[i] = ainfo[j]; + if ( !acc_eq ( ainfo[i], ainfo[i - 1]) ) i++; + } + if ( i == j ) return; + ainfo.resize ( len - (j -i)); + //DEBUG_L("len out %d, ", ainfo.size ()); +} + +static void +print_acc_info ( FILE *file, acc_info_t *ainfo ) +{ + //DEBUG_L("print_acc_info: ainfo %p\n", ainfo); + fprintf ( file, "%s%s%s%s%s%s\n", + ainfo->base_info.a_def_def ? ", deflt_def" : "", + ainfo->base_info.a_decl ? ", decl" : "", + ainfo->base_info.a_func ? ", a_func" : "", + ainfo->base_info.has_induct_var_acc ? ", induct" : "", + ainfo->base_info.multi_induct ? ", multi" : "", + ainfo->base_info.complicated ? ", complicated" : ""); + fprintf ( file, " base var "); + flexible_print ( stderr, ainfo->base_info.acc_base, 0, (dump_flags_t)0); + if ( ainfo->base_info.has_induct_var_acc ) + { + fprintf ( file, ", induc var "); + flexible_print ( stderr, ainfo->base_info.acc_base, + 0, (dump_flags_t)0); + } + fprintf ( file, ", field "); + flexible_print ( stderr, ainfo->field, 0, (dump_flags_t)0); + if ( ainfo->reorg ) + { + fprintf ( file, ", reorg of "); + flexible_print ( stderr, ainfo->reorg->gcc_type, + 0, (dump_flags_t)0); + } + fprintf ( file, "\n"); +} + +static void +print_acc_infos ( FILE *file, std::vector <acc_info_t> ainfo ) +{ + fprintf ( file, "print_acc_infos:\n"); + unsigned i; + unsigned len = ainfo.size (); + + for ( i = 0; i < len; i++ ) + { + fprintf ( file, "[%d] ", i); + print_acc_info ( file, &ainfo[i]); + } +} + + +// decls < default defs < defined by function +static bool +acc_lt_acc_category ( const acc_info_t& a, const acc_info_t& b ) +{ + int ord_a = a.base_info.a_decl ? 1 : a.base_info.a_def_def ? 2 : 3; + int ord_b = b.base_info.a_decl ? 1 : b.base_info.a_def_def ? 2 : 3; + if ( ord_a < ord_b ) return true; + if ( ord_a > ord_b ) return false; + switch ( ord_a ) { + case 1: + // The field isn't there for decls, it's the index. Ignoring the + // index is harmless. This is becauseif if we take an arbitary + // small number of iterations of a loop, then all the permutations + // of the accesses in those iterations touch the same number of + // cache lines (just in a different order.) + return false; + case 2: + { + if ( a.access < b.access ) return true; + if ( a.access > b.access ) return false; + return a.field < b.field; + } + case 3: + { + if ( a.base_info.function < b.base_info.function ) return true; + if ( a.base_info.function > b.base_info.function ) return false; + return a.field < b.field; + } + } +} + +// Complicated is less than noncomplicated and null reorgs are less than non +// null reorgs. +static bool +acc_lt ( const acc_info_t& a, const acc_info_t& b ) +{ + if ( a.base_info.complicated && !b.base_info.complicated ) return true; + if ( !a.base_info.complicated && !b.base_info.complicated ) return false; + if ( a.reorg == NULL ) + { + if ( b.reorg != NULL ) return true; + // compare non_reorg_bit + return acc_lt_acc_category ( a, b); + } + else + { + if ( b.reorg == NULL ) return false; + if ( a.reorg < b.reorg ) return true; + if ( a.reorg > b.reorg ) return false; + // compare non_reorg_bit + return acc_lt_acc_category ( a, b); + } +} + +static bool +acc_eq ( const acc_info_t& a, const acc_info_t& b ) +{ + // nothing complicated is equal to anything else. Being complicated + // is basically saying that little is really know about it and it's + // difficult if not meaningless to analyze in depth given this + // framework. + if ( a.base_info.complicated || b.base_info.complicated ) return false; + if ( a.reorg != b.reorg ) return false; + int ord_a = a.base_info.a_decl ? 1 : a.base_info.a_def_def ? 2 : 3; + int ord_b = b.base_info.a_decl ? 1 : b.base_info.a_def_def ? 2 : 3; + if ( ord_a != ord_b ) return false; + switch ( ord_a ) { + case 1: + case 2: + { + if ( a.access != b.access ) return false; + } + case 3: + { + if ( a.base_info.function != b.base_info.function ) return false; + } + } + return a.field == b.field; +} + +static bool +all_but_field_eq ( const acc_info_t& a, const acc_info_t& b ) +{ + // nothing complicated is equal to anything else. Being complicated + // is basically saying that little is really know about it and it's + // difficult if not meaningless to analyze in depth given this + // framework. + if ( a.base_info.complicated || b.base_info.complicated ) return false; + if ( a.reorg != b.reorg ) return false; + int ord_a = a.base_info.a_decl ? 1 : a.base_info.a_def_def ? 2 : 3; + int ord_b = b.base_info.a_decl ? 1 : b.base_info.a_def_def ? 2 : 3; + if ( ord_a != ord_b ) return false; + switch ( ord_a ) { + case 1: + case 2: + { + return a.access == b.access; + } + case 3: + { + return a.base_info.function == b.base_info.function; + } + } } #define SINGLE_POOL_SLOPE \ @@ -2246,18 +2863,248 @@ is_array_access( tree acc) } static void -account_for_use( tree acc, std::vector <acc_info_t> *acc_info) +account_for_access ( tree access, tree field, std::vector <acc_info_t> *acc_info, Info_t *info) { - // determine element of access - // find field access number i - // find var v - varpool_node *v; - int i; - // TBD - acc_info_t ai = { v, i}; + //DEBUG_A("account_for_use var: "); + //DEBUG_F(flexible_print, stderr, access, 0, (dump_flags_t)0); + //DEBUG(", field: "); + //DEBUG_F(flexible_print, stderr, field, 1, (dump_flags_t)0); + + // assert might eventually make sense but not yet + //gcc_assert ( TREE_CODE ( ssa_var) == SSA_NAME); + acc_info_t ai; + //ai.v = SSA_NAME_VAR ( ssa_var); + ai.access = access; // TBD We need to see if we can find the decl + ai.field = field; + ai.reorg = tree_contains_a_reorgtype ( access, info); + analyze_access ( access, &ai); + // don't count this acces if there is no associated induction variable + if ( !ai.base_info.has_induct_var_acc ) return; + // Otherwise add the access acc_info->push_back( ai); } +static void +tmasn_helper ( tree t, int indent, std::set<tree> *already ) +{ + //DEBUG_A(""); + fprintf( stderr, "%*s", indent, " "); + indent += 4; + flexible_print ( stderr, t, 0, (dump_flags_t)0); + if ( already->find (t) != already->end () ) + { + fprintf( stderr, " <Induction>\n"); + return; + } + else + { + fprintf( stderr, "\n"); + } + //DEBUG_L("code: %s\n", code_str(TREE_CODE (t))); + if ( TREE_CODE (t) == SSA_NAME ) + { + already->insert (t); + gimple *stmt = SSA_NAME_DEF_STMT (t); + fprintf( stderr, "%*sSSA_NAME defined in: ", indent - 4, " "); + print_gimple_stmt( stderr, stmt, TDF_DETAILS); + if ( gimple_code ( stmt) == GIMPLE_PHI ) + { + gphi *phi_stmt = dyn_cast <gphi *> ( stmt); + for (int i = 0; i < gimple_phi_num_args (phi_stmt); i++) + { + tree *arg = gimple_phi_arg_def_ptr (phi_stmt, i); + tmasn_helper ( *arg, indent, already); + } + } + else + { + bool a_ass = gimple_code ( stmt) == GIMPLE_ASSIGN; + bool a_call = gimple_code ( stmt) == GIMPLE_CALL; + // This was being triggered an add: op = op + op + //gcc_assert ( a_ass || a_call ); + + if ( a_call ) + { + for ( int i = 0; i < gimple_call_num_args ( stmt); i++ ) + { + tmasn_helper ( gimple_call_arg ( stmt, i) , indent, already); + } + } + else + { + // Note, start with one to skip lhs op. + for ( int i = 1; i < gimple_num_ops ( stmt); i++ ) + { + tmasn_helper ( gimple_op ( stmt, i) , indent, already); + } + } + } + return; + } + if ( DECL_P ( t) ) + { + return; + } + if ( TREE_CODE ( t) == MEM_REF ) + { + tree t_0 = TREE_OPERAND ( t, 0); + fprintf( stderr, "%*sMEM_REF t_0: ", indent - 4, " "); + flexible_print ( stderr, t_0, 1, (dump_flags_t)0); + tmasn_helper ( t_0 , indent, already); + return; + } + if ( TREE_CODE ( t) == INTEGER_CST ) return; + fprintf ( stderr, "unanticipated TREE_CODE\n"); + gcc_assert ( 0); +} + +static void +tell_me_about_ssa_name ( tree ssa_name, int indent) +{ + fprintf(stderr,"about:\n"); + std::set<tree> already; + tmasn_helper ( ssa_name, indent, &already); +} + +static unsigned insane_helper; + +static void +an_ac_helper ( tree t, int indent, std::set<tree> *already, acc_info_t *ainfo ) +{ + gcc_assert ( insane_helper < 100 ); + insane_helper++; + acc_base_info_t *binfo = &ainfo->base_info; + //DEBUG_A("%*s", indent, " "); + indent += 4; + //DEBUG_F( flexible_print, stderr, t, 0, (dump_flags_t)0); + if ( already->find (t) != already->end () ) + { + //DEBUG(" <Induction>\n"); + binfo->multi_induct = + binfo->multi_induct || binfo->has_induct_var_acc; + binfo->induct_base = t; + binfo->has_induct_var_acc = true; + return; + } + else + { + //DEBUG("\n"); + + } + //DEBUG_A("%*scode: %s\n", indent, " ", code_str(TREE_CODE (t))); + if ( TREE_CODE (t) == SSA_NAME ) + { + already->insert (t); + gimple *stmt = SSA_NAME_DEF_STMT (t); + //DEBUG_A("%*sSSA_NAME defined in: ", indent, " "); + //DEBUG_F(print_gimple_stmt, stderr, stmt, TDF_DETAILS); + if ( SSA_NAME_IS_DEFAULT_DEF ( t ) ) + { + binfo->acc_base = t; + binfo->complicated = + binfo->complicated || binfo->a_def_def || binfo->a_decl || binfo->a_func; + binfo->a_def_def = true; + } + if ( gimple_code ( stmt) == GIMPLE_PHI ) + { + gphi *phi_stmt = dyn_cast <gphi *> ( stmt); + for (int i = 0; i < gimple_phi_num_args (phi_stmt); i++) + { + tree *arg = gimple_phi_arg_def_ptr (phi_stmt, i); + an_ac_helper ( *arg, indent, already, ainfo); + } + } + else + { + bool a_ass = gimple_code ( stmt) == GIMPLE_ASSIGN; + bool a_call = gimple_code ( stmt) == GIMPLE_CALL; + // This was being triggered an add: op = op + op + //gcc_assert ( a_ass || a_call ); + + if ( a_call ) + { + binfo->acc_base = t; + binfo->complicated = + binfo->complicated || binfo->a_def_def || binfo->a_decl || binfo->a_func; + binfo->a_func = true; + binfo->function = stmt; + // Question, do we want to walk the call arguements??? + // Because how do the arguments effect the return value? + // It's basically unknow so we shouldn't walk the + // arguemets. + // + for ( int i = 0; i < gimple_call_num_args ( stmt); i++ ) + { + an_ac_helper ( gimple_call_arg ( stmt, i), indent, already, ainfo); + } + } + else + { + // Note, start with one to skip lhs op. + for ( int i = 1; i < gimple_num_ops ( stmt); i++ ) + { + an_ac_helper ( gimple_op ( stmt, i), indent, already, ainfo); + } + } + } + return; + } + if ( DECL_P ( t) ) + { + binfo->acc_base = t; + binfo->complicated = + binfo->complicated || binfo->a_def_def || binfo->a_decl || binfo->a_func; + binfo->a_decl = true; + + //DEBUG_A("field (index) for a_decl: "); + //DEBUG_F(flexible_print, stderr, ainfo->field, 1, (dump_flags_t)0); + + if ( TREE_CODE ( t) != FIELD_DECL ) + { + an_ac_helper ( ainfo->field, indent, already, ainfo); + } + return; + } + if ( TREE_CODE ( t) == MEM_REF ) + { + tree t_0 = TREE_OPERAND ( t, 0); + //DEBUG_A("%*sMEM_REF t_0: ", indent, " "); + //DEBUG_F(flexible_print, stderr, t_0, 1, (dump_flags_t)0); + an_ac_helper ( t_0 , indent, already, ainfo); + return; + } + if ( TREE_CODE ( t) == COMPONENT_REF ) + { + tree t_0 = TREE_OPERAND ( t, 0); + //DEBUG_A("%*sCOMPONENT_REF t_0: ", indent, " "); + //DEBUG_F(flexible_print, stderr, t_0, 1, (dump_flags_t)0); + an_ac_helper ( t_0 , indent, already, ainfo); + return; + } + if ( TREE_CODE ( t) == INTEGER_CST ) return; + if ( TREE_CODE ( t) == ADDR_EXPR ) return; + fprintf ( stderr, "Unanticipated TREE_CODE\n"); + gcc_assert ( 0); +} + +static void +analyze_access ( tree access, acc_info_t *acc_info) +{ + insane_helper = 0; + acc_base_info_t *base_info = &acc_info->base_info; + //DEBUG_A("analyze_access:\n"); + base_info->a_def_def = false; + base_info->a_decl = false; + base_info->a_func = false; + base_info->has_induct_var_acc = false; + base_info->multi_induct = false; + base_info->complicated = false; + base_info->acc_base = NULL; + base_info->induct_base = NULL; + std::set<tree> already; + an_ac_helper ( access, 4, &already, acc_info); +} + // create_new_types has to crawl "all" the // types, create new types and transform @@ -2527,10 +3374,10 @@ static basic_block make_bb ( char *msg, basic_block prev_bb ) { basic_block ret = create_empty_bb ( prev_bb); - DEBUG_A( "make_bb ( %s, <bb %d>/%p ): <bb %d>/%p, prev: <bb %d>/%p, next: <bb %d>/%p\n", - msg, prev_bb->index, prev_bb, - ret->index, ret, - ret->prev_bb->index, ret->prev_bb, - ret->next_bb->index, ret->next_bb); + //DEBUG_A( "make_bb ( %s, <bb %d>/%p ): <bb %d>/%p, prev: <bb %d>/%p, next: <bb %d>/%p\n", + // msg, prev_bb->index, prev_bb, + // ret->index, ret, + // ret->prev_bb->index, ret->prev_bb, + // ret->next_bb->index, ret->next_bb); return ret; } diff --git a/gcc/ipa-structure-reorg.c b/gcc/ipa-structure-reorg.c index 639a1e876f3..96f07c11aeb 100644 --- a/gcc/ipa-structure-reorg.c +++ b/gcc/ipa-structure-reorg.c @@ -140,7 +140,7 @@ ipa_structure_reorg ( void) cgraph_node* node; FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node) node->get_untransformed_body (); - DEBUG_F( ssa_check, stderr, Show_everything, Do_not_fail, false, true); + //DEBUG_F( ssa_check, stderr, Show_everything, Do_not_fail, false, true); setup_debug_flags ( &info); initial_debug_info ( &info); @@ -153,10 +153,10 @@ ipa_structure_reorg ( void) return true; } - DEBUG_L("after reorg_analysis\n"); + //DEBUG_L("after reorg_analysis\n"); bool qualified = reorg_qualification(&info); - DEBUG_L("after reorg_qualification\n"); + //DEBUG_L("after reorg_qualification\n"); //DEBUG_L(""); //DEBUG_F(wolf_fence, &info); @@ -186,6 +186,8 @@ ipa_structure_reorg ( void) } + fprintf (stderr, "info.show_all_reorg_cands_in_detail %s\n", + info.show_all_reorg_cands_in_detail ? "true" : "false"); if ( info.show_all_reorg_cands_in_detail ) { fprintf ( info.reorg_dump_file, "Qualified the following types:\n"); @@ -193,7 +195,7 @@ ipa_structure_reorg ( void) } reorg_common_middle_code( &info); // ??? might not amount to anything - DEBUG_L("after reorg_common_middle_code\n"); + //DEBUG_L("after reorg_common_middle_code\n"); //DEBUG_L(""); //DEBUG_F(wolf_fence, &info); @@ -230,6 +232,7 @@ setup_debug_flags ( Info *info) info->show_all_reorg_cands = true; info->show_all_reorg_cands_in_detail = dump_flags & TDF_DETAILS; info->show_prog_decls = true; + info->show_perf_qualify = true; info->show_delete = dump_flags & TDF_DETAILS; info->show_new_BBs = dump_flags & TDF_DETAILS; info->show_transforms = dump_flags & TDF_DETAILS; @@ -274,7 +277,7 @@ reorg_analysis ( Info *info) // specified since I am not sure what this function should // concretely do. // Eric this is not really helping me... ;-) - DEBUG_L("reorg_analysis: entered\n"); + //DEBUG_L("reorg_analysis: entered\n"); #if INTEGRATION_FUNCTIONAL const bool run_escape_analysis = flag_ipa_dead_field_eliminate && !flag_ipa_instance_interleave && !flag_ipa_field_reorder; if (run_escape_analysis) @@ -321,37 +324,42 @@ reorg_analysis ( Info *info) gsi_next ( &gsi) ) { gimple *stmt = gsi_stmt ( gsi); - DEBUG_L ( ""); - DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); - INDENT(2); + //DEBUG_L ( ""); + //DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); + //INDENT(2); if ( is_gimple_call ( stmt) ) { // next line has issues but the mechanism is sound tree t = *gimple_call_lhs_ptr ( stmt); - DEBUG_A( "t %p\n", t); + //DEBUG_A( "t %p\n", t); // Calls to a function returning void are skipped. if ( t != NULL ) { - DEBUG_A( "t: "); - DEBUG_F( flexible_print, stderr, t, 1, (dump_flags_t)0); + //DEBUG_A( "t: "); + //DEBUG_F( flexible_print, stderr, t, 1, (dump_flags_t)0); tree type = TREE_TYPE( t); - DEBUG_A( "type: "); - DEBUG_F( flexible_print, stderr, type, 1, (dump_flags_t)0); + //DEBUG_A( "type: "); + //DEBUG_F( flexible_print, stderr, type, 1, (dump_flags_t)0); //tree bt = base_type_of ( t); tree bt = base_type_of ( type); if ( TREE_CODE( bt) != RECORD_TYPE && TREE_CODE( bt) != VOID_TYPE) { - DEBUG_A( "TREE_CODE( bt) == %s\n", code_str( TREE_CODE ( bt))); - DEBUG_A(""); - DEBUG_F(flexible_print, stderr, bt, 1, (dump_flags_t)0); - INDENT(-2); + //DEBUG_A( "TREE_CODE( bt) == %s\n", code_str( TREE_CODE ( bt))); + //DEBUG_A(""); + //DEBUG_F(flexible_print, stderr, bt, 1, (dump_flags_t)0); + //INDENT(-2); continue; } if ( TREE_CODE( bt) == VOID_TYPE ) { - // find the use of lhs. If is an assign + // Find the use of lhs. If is an assign // get use the base type of it's lhs. - // Otherwise never mind. + // Otherwise never mind. Note, there + // can be multiple uses but find the "one" + // that's a simple assignment to a typed + // variable. + + #if 0 gimple *use_stmt; use_operand_p immuse; bool yup_a_use = single_imm_use ( t, &immuse, &use_stmt); @@ -364,19 +372,58 @@ reorg_analysis ( Info *info) { tree use_lhs = gimple_assign_lhs ( use_stmt); bt = base_type_of ( TREE_TYPE ( use_lhs)); + //DEBUG_A("found bt: "); + //DEBUG_F(flexible_print, stderr, bt, 1, (dump_flags_t)0); } else - continue; + { + //DEBUG_A("bailed on base type of complicated case\n"); + //INDENT(-2); + continue; + } + #endif + + tree ssa_name = gimple_call_lhs( stmt); + gimple *use_stmt; + imm_use_iterator iter; + int num_bt = 0; + FOR_EACH_IMM_USE_STMT ( use_stmt, iter, ssa_name) + { + //DEBUG_A("use_stmt: "); + //DEBUG_F ( print_gimple_stmt, stderr, use_stmt, 0); + if ( is_assign_from_ssa ( use_stmt ) ) + { + //DEBUG_A("is assign from ssa\n"); + tree lhs_assign = gimple_assign_lhs( use_stmt); + tree lhs_type = TREE_TYPE ( lhs_assign); + tree lhs_base_type = base_type_of ( lhs_type); + if ( TREE_CODE( lhs_base_type) != VOID_TYPE ) + { + //DEBUG_A("not void\n"); + num_bt++; + bt = lhs_base_type; + } + } + } + if ( num_bt != 1 ) + { + //DEBUG_L("bailed on base type of complicated case\n"); + //INDENT(-2); + continue; + } } + + + bool alloc_trigger = is_reorg_alloc_trigger ( stmt); // find if in reorgtypes and get the info (in one call) ReorgType_t *ri = get_reorgtype_info ( bt, info); - if ( ri != NULL && is_reorg_alloc_trigger ( stmt) ) + if ( ri != NULL && alloc_trigger ) { - DEBUG_L( "Found allocaion: \n"); - DEBUG_A( " Reorg: "); - DEBUG_F( print_reorg, stderr, 0, ri); - DEBUG("\n"); + //DEBUG_L( "Found allocaion: \n"); + //DEBUG_A( " Reorg: "); + //DEBUG_F( print_reorg, stderr, 0, ri); + //DEBUG("\n"); // TBD this needs to increment with the execution count // instead of one. I hope the build-in block count estimation // will work or a DIY solution might be called for. @@ -384,13 +431,13 @@ reorg_analysis ( Info *info) } } } - INDENT(-2); + //INDENT(-2); } } } - DEBUG_L( "possible deletes:\n"); - INDENT(2); + //DEBUG_L( "possible deletes:\n"); + //INDENT(2); // It's LOT more clear to use an iterator here TBD for ( int i = 0; i < info->reorg_type->size (); i++ ) { @@ -403,13 +450,21 @@ reorg_analysis ( Info *info) } // Note when multi-pools are enabled the test should be // "n == 0" but until then... - DEBUG_A("%d pools\n",n) + //DEBUG_A("%d pools\n",n) if ( n != 1 ) { + if ( info->show_all_reorg_cands_in_detail ) + { + fprintf ( info->reorg_dump_file, "Delete ReorgType: "); + flexible_print ( info->reorg_dump_file, + (*(info->reorg_type))[i].gcc_type, + 0, (dump_flags_t)0); + fprintf ( info->reorg_dump_file, ", it has %d pools\n", n); + } delete_reorgtype ( &(*(info->reorg_type))[i], info); } } - INDENT(-2); + //INDENT(-2); //DEBUG_L("after reorg_analysis\n"); remove_deleted_types ( info, &reorg_analysis_debug); @@ -468,7 +523,9 @@ find_decls_and_types ( Info *info) if ( TREE_CODE ( base) == RECORD_TYPE ) { // skip if found before - if ( typeset.find ( base) != typeset.end () ) + tree tmv_type = TYPE_MAIN_VARIANT ( base); + tree tmv_base = tmv_type ? tmv_type : base; + if ( typeset.find ( tmv_base) != typeset.end () ) { //DEBUG_L( " not found\n"); continue; @@ -478,9 +535,9 @@ find_decls_and_types ( Info *info) } #if USE_REORG_TYPES - add_reorg_type ( base, info); + add_reorg_type ( tmv_base, info); #endif - typeset.insert ( base); // ??? + typeset.insert ( tmv_base); // ??? } } @@ -515,16 +572,18 @@ find_decls_and_types ( Info *info) if ( TREE_CODE ( base) == RECORD_TYPE) { - if ( typeset.find ( base) != typeset.end () ) + tree tmv_type = TYPE_MAIN_VARIANT ( base); + tree tmv_base = tmv_type ? tmv_type : base; + if ( typeset.find ( tmv_base) != typeset.end () ) { //INDENT(-2) continue; } #if USE_REORG_TYPES - add_reorg_type ( base, info); + add_reorg_type ( tmv_base, info); #endif - typeset.insert ( base); // ??? + typeset.insert ( tmv_base); // ??? } } //INDENT(-2); @@ -720,6 +779,8 @@ find_decls_and_types ( Info *info) static void add_reorg_type ( tree base, Info *info) { + tree tmv_type = TYPE_MAIN_VARIANT ( base); + tree type2add = tmv_type ? tmv_type : base; ReorgType_t rt = { 0, true, base, NULL, NULL, false, false, false, { 0}, { 0}, { 0, 0, 0, NULL, 0.0, 0.0, false}}; @@ -845,11 +906,19 @@ disq_str_in_str_or_union_helper ( tree type, //tree base = base_type_of ( field_type); if ( TREE_CODE ( field_type) == RECORD_TYPE ) // base to field type { - DEBUG( "RECORD\n"); + //DEBUG( "RECORD\n"); ReorgType_t *rinfo = get_reorgtype_info ( field_type, info); // base to field type if ( rinfo != NULL ) { + if ( info->show_all_reorg_cands_in_detail ) + { + fprintf ( info->reorg_dump_file, "Delete ReorgType: "); + flexible_print ( info->reorg_dump_file, + rinfo->gcc_type, + 0, (dump_flags_t)0); + fprintf ( info->reorg_dump_file, ", Structure in structure.\n"); + } delete_reorgtype ( rinfo, info); } else { disq_str_in_str_or_union_helper ( field_type, typeset, info ); // base to field type @@ -922,7 +991,11 @@ transformation_legality ( Info *info) // GIMPLE_IL sizeof tree expr // memmove(&astruct_1, &astruct_2, sizeof(struct astruct_s)); // memmove(&astruct_1.b, &astruct_2.b, 2*sizeof(_Bool)); - const bool run_escape_analysis = flag_ipa_dead_field_eliminate && !flag_ipa_instance_interleave && !flag_ipa_field_reorder; + const bool run_escape_analysis = + flag_ipa_dead_field_eliminate && + !flag_ipa_instance_interleave && + !flag_ipa_field_reorder; + if (run_escape_analysis) { bool retval = !info->is_non_escaping_set_empty(); @@ -953,7 +1026,8 @@ transformation_legality ( Info *info) case Not_Supported: //DEBUG_L("deleting %d reorgs for unsuported stmt: ", num); //DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); - disqualify_all_reorgtypes_of ( stmt, num, info); + // TBD This is not working + //disqualify_all_reorgtypes_of ( stmt, num, info); case ReorgT_UserFunc: // TBD ReorgT_Ptr2Zero does not catch all cases of // setting a reorg pointer to zero. One that I @@ -1005,6 +1079,7 @@ transformation_legality_debug ( Info *info, ReorgType *reorg ) static void reorg_common_middle_code ( Info *info) { + if ( BYPASS_TRANSFORM ) return; modify_declarations( info); } @@ -1098,13 +1173,26 @@ modify_declarations ( Info *info) static void disqualify_all_reorgtypes_of ( gimple *stmt, int num, Info *info) { - DEBUG_L("disqualify %d reorgtypes of: ", num); - DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); + //DEBUG_L("disqualify %d reorgtypes of: ", num); + //DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); + if ( info->show_all_reorg_cands_in_detail ) + { + print_gimple_stmt( info->reorg_dump_file, stmt, 0); + } int i; for ( i = 0; i < num; i++ ) { ReorgType_t *reorg_type = get_reorgtype ( stmt, info, i); + //DEBUG_A( "reorg_type = %p\n", reorg_type); + if ( info->show_all_reorg_cands_in_detail ) + { + fprintf ( info->reorg_dump_file, " Delete ReorgType: "); + flexible_print ( info->reorg_dump_file, + (*(info->reorg_type))[i].gcc_type, + 0, (dump_flags_t)0); + fprintf ( info->reorg_dump_file, ", because of gimple above.\n"); + } delete_reorgtype ( reorg_type, info); } } @@ -1128,9 +1216,9 @@ static tree modify_func_type ( struct function *func, Info *info ) { tree func_type = TREE_TYPE ( func->decl); - DEBUG_L("old func_type = "); - DEBUG_F( flexible_print, stderr, func_type, 1, (dump_flags_t)0); - INDENT(4); + //DEBUG_L("old func_type = "); + //DEBUG_F( flexible_print, stderr, func_type, 1, (dump_flags_t)0); + //INDENT(4); tree new_type; tree func_ret_type = TREE_TYPE ( func_type); tree base = base_type_of ( func_ret_type); @@ -1170,13 +1258,14 @@ modify_func_type ( struct function *func, Info *info ) ri = get_reorgtype_info ( base, info); if ( ri != NULL ) { + int levels = number_of_levels ( type_of_arg ); if ( number_of_levels ( type_of_arg ) == 1 ) { new_arg_type = TYPE_MAIN_VARIANT ( ri->pointer_rep); } else { - gcc_assert(0); + new_arg_type = make_multilevel ( ri->pointer_rep, levels); } } else @@ -1193,13 +1282,13 @@ modify_func_type ( struct function *func, Info *info ) new_args = nreverse ( new_args); TREE_CHAIN ( last) = void_list_node; - DEBUG_A("new args = "); - DEBUG_F( flexible_print, stderr, new_args, 1, (dump_flags_t)0); - INDENT(-4); + //DEBUG_A("new args = "); + //DEBUG_F( flexible_print, stderr, new_args, 1, (dump_flags_t)0); + //INDENT(-4); new_type = build_function_type ( func_ret_type, new_args); - DEBUG_L("new_type (func) = "); - DEBUG_F( flexible_print, stderr, new_type, 1, (dump_flags_t)0); + //DEBUG_L("new_type (func) = "); + //DEBUG_F( flexible_print, stderr, new_type, 1, (dump_flags_t)0); TREE_TYPE ( func->decl) = new_type; return new_type; } @@ -1237,6 +1326,18 @@ tree prev_type; return levels; } +tree +make_multilevel( tree base_type, int levels_indirection) +{ + if ( levels_indirection == 0 ) + return base_type; + else + { + tree lower = make_multilevel ( base_type, levels_indirection - 1); + return build_pointer_type ( lower); + } +} + static bool modify_func_decl_core ( struct function *func, Info *info) { @@ -1429,14 +1530,14 @@ modify_decl_core ( tree *location, Info *info) void delete_reorgtype ( ReorgType_t *rt, Info *info ) { - DEBUG_L( "delete_reorgtype( %s ):", type_name_to_str( TYPE_NAME( rt->gcc_type))); + //DEBUG_L( "delete_reorgtype( %s ):", type_name_to_str( TYPE_NAME( rt->gcc_type))); if ( !rt->delete_me ) { - DEBUG( "TO DELETE\n"); + //DEBUG( "TO DELETE\n"); info->num_deleted++; rt->delete_me = true; } else { - DEBUG( "SKIP\n"); + //DEBUG( "SKIP\n"); } } @@ -1457,38 +1558,40 @@ undelete_reorgtype ( ReorgType_t *rt, Info *info ) ReorgTransformation reorg_recognize ( gimple *stmt, cgraph_node* node, Info_t *info ) { - DEBUG_L ( "ReorgTransformation reorg_recognize for: "); - DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); - INDENT(2); + //DEBUG_L ( "ReorgTransformation reorg_recognize for: "); + //DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); + //INDENT(2); switch ( gimple_code( stmt) ) { case GIMPLE_ASSIGN: { - DEBUG_L("GIMPLE_ASSIGN:\n"); + //DEBUG_L("GIMPLE_ASSIGN:\n"); tree lhs = gimple_assign_lhs ( stmt); enum tree_code rhs_code = gimple_assign_rhs_code ( stmt); if ( gimple_assign_single_p ( stmt) ) { - DEBUG_L("gimple_assign_single_p() = true\n"); - INDENT(2); + //DEBUG_L("gimple_assign_single_p() = true\n"); + //INDENT(2); tree rhs = gimple_assign_rhs1 ( stmt); - enum ReorgOpTrans lhs_op = recognize_op ( lhs, info); + enum ReorgOpTrans lhs_op = recognize_op ( lhs, true, info); switch ( lhs_op ) { case ReorgOpT_Pointer: // "a" - DEBUG_L("case ReorgOpT_Pointer\n"); - INDENT(-4); - switch ( recognize_op ( rhs, info) ) + //DEBUG_L("case ReorgOpT_Pointer\n"); + //INDENT(-4); + switch ( recognize_op ( rhs, true, info) ) { case ReorgOpT_Scalar: - if ( integer_zerop ( rhs) ) { - return ReorgT_Ptr2Zero; + if ( integer_zerop ( rhs) ) + { + return ReorgT_Ptr2Zero; + } + // If we get here this is clearly really odd code + // so we need to bail out. + return Not_Supported; } - // If we get here this is clearly really odd code - // so we need to bail out. - return Not_Supported; case ReorgOpT_Temp: // t return ReorgT_ElemAssign; case ReorgOpT_Address: // "&x[i]" @@ -1497,9 +1600,9 @@ reorg_recognize ( gimple *stmt, cgraph_node* node, Info_t *info ) return Not_Supported; } case ReorgOpT_Struct: // "s" - DEBUG_L("case ReorgOpT_Struct\n"); - INDENT(-4); - switch ( recognize_op ( rhs, info) ) + //DEBUG_L("case ReorgOpT_Struct\n"); + //INDENT(-4); + switch ( recognize_op ( rhs, true, info) ) { case ReorgOpT_Deref: // "*a" case ReorgOpT_Array: // "x[i]" @@ -1514,9 +1617,9 @@ reorg_recognize ( gimple *stmt, cgraph_node* node, Info_t *info ) return Not_Supported; } case ReorgOpT_Deref: // "*a" - DEBUG_L("case ReorgOpT_Deref\n"); - INDENT(-4); - switch ( recognize_op ( rhs, info) ) + //DEBUG_L("case ReorgOpT_Deref\n"); + //INDENT(-4); + switch ( recognize_op ( rhs, true, info) ) { case ReorgOpT_Deref: // "*a" case ReorgOpT_Struct: // "s" @@ -1526,9 +1629,9 @@ reorg_recognize ( gimple *stmt, cgraph_node* node, Info_t *info ) return Not_Supported; } case ReorgOpT_Array: // "x[i]" - DEBUG_L("case ReorgOpT_Array\n"); - INDENT(-4); - switch ( recognize_op ( rhs, info) ) + //DEBUG_L("case ReorgOpT_Array\n"); + //INDENT(-4); + switch ( recognize_op ( rhs, true, info) ) { case ReorgOpT_Struct: // "s" case ReorgOpT_Deref: // "*a" @@ -1539,9 +1642,9 @@ reorg_recognize ( gimple *stmt, cgraph_node* node, Info_t *info ) } case ReorgOpT_Temp: // t case ReorgOpT_Scalar: // "z" - DEBUG_L("case ReorgOpT_%s\n", lhs_op == ReorgOpT_Temp ? "Temp" : "Scalar"); - INDENT(-4); - switch ( recognize_op( rhs, info) ) + //DEBUG_L("case ReorgOpT_%s\n", lhs_op == ReorgOpT_Temp ? "Temp" : "Scalar"); + //INDENT(-4); + switch ( recognize_op( rhs, true, info) ) { case ReorgOpT_Scalar: // "z" case ReorgOpT_Temp: // "t" @@ -1553,43 +1656,44 @@ reorg_recognize ( gimple *stmt, cgraph_node* node, Info_t *info ) } case ReorgOpT_Indirect: // "a->f" case ReorgOpT_AryDir: // "x[i].f" - DEBUG_L("case ReorgOpT_%s\n", lhs_op == ReorgOpT_Indirect ? "Indirect" : "AryDir"); - INDENT(-4); - switch ( recognize_op ( rhs, info) ) + //DEBUG_L("case ReorgOpT_%s\n", lhs_op == ReorgOpT_Indirect ? "Indirect" : "AryDir"); + //INDENT(-4); + switch ( recognize_op ( rhs, true, info) ) { + case ReorgOpT_Cst: // k case ReorgOpT_Temp: // t case ReorgOpT_Scalar: // "z" case ReorgOpT_Indirect: // "a->f" case ReorgOpT_AryDir: // "x[i].f" return ReorgT_ElemAssign; + case ReorgOpT_Cst0: + return ReorgT_Ptr2Zero; default: return Not_Supported; } default: - INDENT(-4); + //INDENT(-4); return Not_Supported; - } // switch ( recognize_op ( lhs, info) ) + } // switch ( recognize_op ( lhs, true, info) ) } else { - DEBUG_L("gimple_assign_single_p() = false\n"); - INDENT(2); + //DEBUG_L("gimple_assign_single_p() = false\n"); + //INDENT(2); tree op1 = gimple_assign_rhs1 ( stmt); tree op2 = gimple_assign_rhs2 ( stmt); - DEBUG_L("op1 = %p, op2 = %p\n", op1, op2); - DEBUG_A(""); - DEBUG_F( print_generic_expr, stderr, op1, (dump_flags_t)-1); - DEBUG("\n"); - + //DEBUG_L("op1 = %p, op2 = %p\n", op1, op2); + //DEBUG_A(""); + //DEBUG_F( flexible_print, stderr, op1, 1, TDF_DETAILS); if ( CONVERT_EXPR_CODE_P ( gimple_assign_rhs_code ( stmt))) { - DEBUG_L("CONVERT_EXPR_CODE_P (...)\n"); - INDENT(-4); + //DEBUG_L("CONVERT_EXPR_CODE_P (...)\n"); + //INDENT(-4); return ReorgT_Convert; } if ( gimple_assign_rhs3 ( stmt) != NULL ) { - DEBUG_L("gimple_assign_rhs3 ( stmt) != NULL\n"); - INDENT(-4); + //DEBUG_L("gimple_assign_rhs3 ( stmt) != NULL\n"); + //INDENT(-4); return Not_Supported; } @@ -1599,8 +1703,8 @@ reorg_recognize ( gimple *stmt, cgraph_node* node, Info_t *info ) ( (POINTER_TYPE_P ( TREE_TYPE( op1)) && integer_zerop ( op2)) || (POINTER_TYPE_P ( TREE_TYPE( op2)) && integer_zerop ( op1))) && ( integer_zerop ( op1) || integer_zerop ( op2) ); - DEBUG_L("zero_case = %s\n", zero_case ? "true" : "false" ); - INDENT(-4); + //DEBUG_L("zero_case = %s\n", zero_case ? "true" : "false" ); + //INDENT(-4); switch ( rhs_code ) { case POINTER_PLUS_EXPR: @@ -1658,12 +1762,12 @@ reorg_recognize ( gimple *stmt, cgraph_node* node, Info_t *info ) } case GIMPLE_CALL: { - DEBUG_L("GIMPLE_CALL:\n"); + //DEBUG_L("GIMPLE_CALL:\n"); struct cgraph_edge *edge = node->get_edge ( stmt); gcc_assert( edge); - DEBUG_L("called function %s gimple_body\n", - edge->callee->has_gimple_body_p() ? "has a" : "has no"); - INDENT(-2); + //DEBUG_L("called function %s gimple_body\n", + // edge->callee->has_gimple_body_p() ? "has a" : "has no"); + //INDENT(-2); if ( gimple_call_builtin_p( stmt, BUILT_IN_CALLOC ) ) return ReorgT_Calloc; if ( gimple_call_builtin_p( stmt, BUILT_IN_MALLOC ) ) return ReorgT_Malloc; if ( gimple_call_builtin_p( stmt, BUILT_IN_REALLOC) ) return ReorgT_Realloc; @@ -1683,15 +1787,15 @@ reorg_recognize ( gimple *stmt, cgraph_node* node, Info_t *info ) } break; case GIMPLE_RETURN: - DEBUG_L("GIMPLE_RETURN:\n"); - INDENT(-2); + //DEBUG_L("GIMPLE_RETURN:\n"); + //INDENT(-2); return ReorgT_Return; break; default: - DEBUG_L ( "didn't support: "); - DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); - DEBUG( "\n"); - INDENT(-2); + //DEBUG_L ( "didn't support: "); + //DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); + //DEBUG( "\n"); + //INDENT(-2); return Not_Supported; } } @@ -1796,76 +1900,133 @@ remove_deleted_types ( Info *info, ReorgFn reorg_fn) } enum ReorgOpTrans -recognize_op ( tree op, Info *info) +recognize_op ( tree op, bool lie, Info *info) { - DEBUG_L("recognize_op: "); - DEBUG_F( flexible_print, stderr, op, 1, TDF_DETAILS); + //DEBUG_L("recognize_op: "); + //DEBUG_F( flexible_print, stderr, op, 1, TDF_DETAILS); enum tree_code op_code = TREE_CODE ( op); - DEBUG_A("opcode = %s\n", code_str( op_code)); - if ( op_code == SSA_NAME ) + //DEBUG_A("opcode = %s\n", code_str( op_code)); + switch ( op_code ) { + case SSA_NAME: // We tried returning ReorgOpT_Scalar. // It caused an assertion failue because // it was incorrectly triggering the ReorgT_Ptr2Zero // case with a bogus RHS. - DEBUG_L(" returns: ReorgOpT_Temp\n"); + //DEBUG_L(" returns: ReorgOpT_Temp\n"); return ReorgOpT_Temp; + case INTEGER_CST: + if ( integer_zerop ( op) ) + { + //DEBUG_A(" returns: ReorgOpT_Cst0\n"); + return ReorgOpT_Cst0; + } + case REAL_CST: + case FIXED_CST: + case STRING_CST: + case COMPLEX_CST: + case CONSTRUCTOR: + case VECTOR_CST: + { + //DEBUG_A(" returns: ReorgOpT_Cst\n"); + return ReorgOpT_Cst; + } } + tree type = TREE_TYPE ( op); + // This type bases approach seems like crap. + // I'm turning it off to see what breaks. + #if 0 if ( type != NULL && POINTER_TYPE_P (type) ) { - DEBUG_L("POINTER_TYPE_P (type) = true\n"); - if ( is_reorg_type ( type, info) ) + //DEBUG_L("POINTER_TYPE_P (type) = true\n"); + bool a_reorg = is_reorg_type ( type, info); + if ( a_reorg || !lie ) { - DEBUG_L(" returns: ReorgOpT_Pointer\n"); + //DEBUG_L(" returns: ReorgOpT_Pointer\n"); return ReorgOpT_Pointer; } else { // This would be for when // the field of a struct element // is a pointer that's not a reorg // point. I.e. ReorgT_ElemAssign. - DEBUG_L(" returns: ReorgOpT_Scalar\n"); + //DEBUG_L(" returns: ReorgOpT_Scalar\n"); return ReorgOpT_Scalar; } } + #endif // This might not occur in practice if ( op_code == RECORD_TYPE ) { // The assumption here is that this // is a reorg type. - DEBUG_L(" returns: ReorgOpT_Struct\n"); + //DEBUG_A(" returns: ReorgOpT_Struct\n"); return ReorgOpT_Struct; } if ( op_code == VAR_DECL ) { tree type = TREE_TYPE ( op); - DEBUG_L(" recursing on type :"); - DEBUG_F( flexible_print, stderr, type, 1, TDF_DETAILS); - return recognize_op ( type, info); + gcc_assert ( type != NULL ); + if ( POINTER_TYPE_P (type) ) + { + bool a_reorg = is_reorg_type ( type, info); + if ( a_reorg || !lie ) + { + //DEBUG_A(" returns: ReorgOpT_Pointer\n"); + return ReorgOpT_Pointer; + } + else + { + // This would be for when the field of a struct + // element is a pointer that's not a reorg + // pointer. I.e. ReorgT_ElemAssign. That is + // this is while lie for a good purpose. + //DEBUG_L(" returns: ReorgOpT_Scalar\n"); + return ReorgOpT_Scalar; + } + } + //DEBUG_L(" returns: ReorgOpT_Scalar\n"); + return ReorgOpT_Scalar; } tree inner_op = TREE_OPERAND( op, 0); tree inner_type = TREE_TYPE ( inner_op); enum tree_code inner_op_code = TREE_CODE ( inner_op); //DEBUG_L("inner_op = "); - //DEBUG_F( print_generic_expr, stderr, inner_op, TDF_DETAILS); - //DEBUG(", TREE_CODE = %s\n", code_str( TREE_CODE(inner_op))); + //DEBUG_F(flexible_print, stderr, inner_op, 0, (dump_flags_t)0); + //DEBUG(", TREE_CODE = %s\n", code_str( inner_op_code)); if ( op_code == ADDR_EXPR ) { //DEBUG_L("op_code == ADDR_EXPR\n"); - if ( inner_op_code == ARRAY_REF - && is_reorg_type ( inner_op, info) ) + if ( inner_op_code == ARRAY_REF ) + { + bool a_reorg = is_reorg_type ( inner_op, info); + if ( a_reorg || !lie ) + { + //DEBUG_L(" returns: ReorgOpT_Address\n"); + return ReorgOpT_Address; + } + } + // TBD shouldn't we be testing for a reorg??? + if ( inner_op_code == VAR_DECL ) { - //DEBUG_L(" returns: ReorgOpT_Address\n"); - return ReorgOpT_Address; + tree var_type = TREE_TYPE ( inner_op ); + bool a_reorg = is_reorg_type ( var_type, info); + if ( a_reorg || !lie ) + { + //DEBUG_L(" returns: ReorgOpT_Address\n"); + return ReorgOpT_Address; + } } } if ( op_code == COMPONENT_REF ) { //DEBUG_L("op_code == COMPONENT_REF\n"); + if ( inner_op_code == INDIRECT_REF ) { //DEBUG_L("TREE_CODE( inner_op) == INDIRECT_REF\n"); - if ( is_reorg_type ( base_type_of ( type), info) ) // inner_type??? + bool a_reorg = is_reorg_type ( base_type_of ( type), info); + if ( a_reorg || !lie ) { //DEBUG_L(" returns: ReorgOpT_Indirect\n"); return ReorgOpT_Indirect; @@ -1876,7 +2037,8 @@ recognize_op ( tree op, Info *info) } if ( inner_op_code == MEM_REF ) { //DEBUG_L("TREE_CODE( inner_op) == MEM_REF\n"); - if ( is_reorg_type ( base_type_of ( inner_type), info) ) + bool a_reorg = is_reorg_type ( base_type_of ( inner_type), info); + if ( a_reorg || !lie ) { //DEBUG_L(" returns: ReorgOpT_Indirect\n"); return ReorgOpT_Indirect; @@ -1885,13 +2047,14 @@ recognize_op ( tree op, Info *info) //DEBUG_L(" returns: ReorgOpT_Scalar\n"); return ReorgOpT_Scalar; } - DEBUG_L("TREE_CODE( inner_op) not INDIRECT_REF or MEM_REF\n"); + //DEBUG_L("TREE_CODE( inner_op) not INDIRECT_REF or MEM_REF\n"); // Note, doesn't this ignore ARRAY_REF of this? // I think it's OK at least until we start supporting // multi-pools. - if ( is_reorg_type ( base_type_of ( inner_type), info) ) + bool a_reorg = is_reorg_type ( base_type_of ( inner_type), info); + if ( a_reorg || !lie ) { - //DEBUG_L(" returns: ReorgOpT_AryDir\n"); + //DEBUG_A(" returns: ReorgOpT_AryDir\n"); return ReorgOpT_AryDir; } // Just normal field reference otherwise... @@ -1901,9 +2064,10 @@ recognize_op ( tree op, Info *info) if ( op_code == ARRAY_REF ) { //DEBUG_L("op_code == ARRAY_REF\n"); - if ( is_reorg_type( base_type_of ( type), info) ) + bool a_reorg = is_reorg_type( base_type_of ( type), info); + if ( a_reorg || !lie ) { - //DEBUG_L(" returns: ReorgOpT_Array\n"); + //DEBUG_A(" returns: ReorgOpT_Array\n"); return ReorgOpT_Array; } //DEBUG_L(" returns: ReorgOpT_Scalar\n"); @@ -1915,9 +2079,10 @@ recognize_op ( tree op, Info *info) // Do we want to chase the base type? // No, we care about (and transform) just // *r and not **...r (where r is a ReorgType.) - if( is_reorg_type ( type, info) ) + bool a_reorg = is_reorg_type ( type, info); + if( a_reorg || !lie ) { - //DEBUG_L(" returns: ReorgOpT_Deref\n"); + //DEBUG_A(" returns: ReorgOpT_Deref\n"); return ReorgOpT_Deref; } //DEBUG_L(" returns: ReorgOpT_Scalar\n"); @@ -1930,6 +2095,8 @@ recognize_op ( tree op, Info *info) bool is_reorg_type( tree rt, Info *info ) { + tree tmv_type = TYPE_MAIN_VARIANT ( rt); + tree type2check = tmv_type ? tmv_type : rt; return get_reorgtype_info ( rt, info) != NULL; } @@ -2082,12 +2249,16 @@ bool same_type_p( tree a, tree b ) ReorgType_t * get_reorgtype_info ( tree type, Info* info) { - DEBUG_L( "get_reorgtype_info\n"); + //DEBUG_L( "get_reorgtype_info: type = "); + //DEBUG_F( flexible_print, stderr, type, 1, (dump_flags_t)0); // Note, I'm going to use the most stupid and slowest possible way // to do this. The advanage is it will be super easy and almost // certainly correct. It will also almost certainly need to be // improved but I get something out there now. + + tree tmv_type = TYPE_MAIN_VARIANT ( type); + tree type2check = tmv_type ? tmv_type : type; for ( std::vector<ReorgType_t>::iterator ri = info->reorg_type->begin (); ri != info->reorg_type->end (); ri++ ) @@ -2097,17 +2268,17 @@ get_reorgtype_info ( tree type, Info* info) // so this is just a place holder until I can get an answer // from the gcc community. Note, this is a big issue. // Remember, the same_type_p here is my own temporary hack. - DEBUG_L(""); - DEBUG_F( print_generic_expr, stderr, type, TDF_DETAILS); - DEBUG("\n"); - if ( same_type_p ( ri->gcc_type, type) ) + //DEBUG_L(""); + //DEBUG_F( print_generic_expr, stderr, type, TDF_DETAILS); + //DEBUG("\n"); + if ( same_type_p ( ri->gcc_type, type2check) ) { - DEBUG_A( " returns %p\n", &(*ri)); + //DEBUG_A( " returns %p\n", &(*ri)); return &(*ri); } } - DEBUG_A( " returns NULL\n"); + //DEBUG_A( " returns NULL\n"); return NULL; } @@ -2124,9 +2295,9 @@ detect_reorg ( tree *tp, int *dummy, void *data) { struct walk_stmt_info *walk_data = ( struct walk_stmt_info *)data; hidden_info_t *hi = ( hidden_info_t *)walk_data->info; - DEBUG_L( "*tp = "); - DEBUG_F( print_generic_expr, stderr, *tp, (dump_flags_t)-1); - DEBUG("\n"); + //DEBUG_L( "*tp = "); + //DEBUG_F( print_generic_expr, stderr, *tp, (dump_flags_t)-1); + //DEBUG("\n"); tree operand = base_type_of ( TREE_TYPE ( *tp)); ReorgType_t *ri = get_reorgtype_info ( operand, hi->info); if ( ri != NULL ) @@ -2140,13 +2311,13 @@ detect_reorg ( tree *tp, int *dummy, void *data) ReorgType_t * contains_a_reorgtype ( gimple *stmt, Info *info) { - DEBUG_L ( "contains_a_reorgtype: "); - DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); - INDENT(2); + //DEBUG_L ( "contains_a_reorgtype: "); + //DEBUG_F ( print_gimple_stmt, stderr, stmt, 0); + //INDENT(2); if ( gimple_code ( stmt) == GIMPLE_PHI ) { - INDENT(-2); + //INDENT(-2); tree base = base_type_of ( TREE_TYPE ( PHI_RESULT ( stmt))); return get_reorgtype_info ( base, info); } @@ -2161,7 +2332,7 @@ contains_a_reorgtype ( gimple *stmt, Info *info) walk_gimple_op ( stmt, detect_reorg, &walk_info); - INDENT(-2); + //INDENT(-2); return hi.found_reorg; } } @@ -2176,7 +2347,8 @@ detect_reorg_in_expr ( tree *tp, int *w_s, void *data) //DEBUG_F( flexible_print, stderr, TREE_TYPE ( *tp), 1, (dump_flags_t)0); tree operand = base_type_of ( TREE_TYPE ( *tp)); //DEBUG_L("operand = %p, ", operand); - DEBUG_F( flexible_print, stderr, operand, 1, (dump_flags_t)0); + + //DEBUG_F( flexible_print, stderr, operand, 1, (dump_flags_t)0); ReorgType_t *ri = get_reorgtype_info ( operand, tre_hi->info); if ( ri != NULL ) { @@ -2244,26 +2416,34 @@ print_base_reorg ( FILE *file, int leading_space, ReorgType_t *reorg, bool detai = identifier_to_locale ( IDENTIFIER_POINTER ( TYPE_NAME ( reorg->gcc_type))); fprintf ( file, "%*s{ type:%s, #%d, ", leading_space, "",text, reorg->id); - if( reorg->do_dead_field_elim ) { - fprintf ( file, "elim:{ "); - // TBD - fprintf ( file, "}, "); - } + if ( reorg->do_dead_field_elim ) + { + fprintf ( file, "elim:{ "); + // TBD + fprintf ( file, "}, "); + } - if( reorg->do_field_reorder ) { - fprintf ( file, "reorder:{ "); - // TBD - fprintf ( file, "}, "); - } + if ( reorg->do_field_reorder ) + { + fprintf ( file, "reorder:{ "); + // TBD + fprintf ( file, "}, "); + } + + if ( reorg->do_instance_interleave ) + { + fprintf ( file, "inter:{ "); + // TBD + fprintf ( file, "%s, ", + reorg->instance_interleave.multi_pool ? "multi" : "single" ); + // TBD When multi-pool implemented (and found) emit pointer_rep. + fprintf ( file, "}, "); + } + else + { + fprintf ( file, "no interleave, "); + } - if( reorg->do_instance_interleave ) { - fprintf ( file, "inter:{ "); - // TBD - fprintf ( file, "%s, ", - reorg->instance_interleave.multi_pool ? "multi" : "single" ); - // TBD When multi-pool implemented (and found) emit pointer_rep. - fprintf ( file, "}, "); - } if ( reorg->reorg_ver_type != NULL ) { // TBD does this belong here? How will the clone be done with elim and @@ -2468,6 +2648,8 @@ print_function ( FILE *file, int leading_space, struct function *func) ReorgType_t * get_reorgtype( gimple *stmt, Info *info, int i) { + //DEBUG_A("get_reorgtype: i = %d, stmt = ", i); + //DEBUG_F(print_gimple_stmt, stderr, stmt, 0); // Looking at operands of statement, when we get to // the ith one, return it. int num_reorgs = 0; @@ -2477,11 +2659,37 @@ get_reorgtype( gimple *stmt, Info *info, int i) { tree op = gimple_op ( stmt, j); if ( tree_contains_a_reorgtype_p ( op, info) ) { - num_reorgs++; if ( num_reorgs == i ) { - return get_reorgtype_info ( op, info); + //DEBUG_A("op = "); + //DEBUG_F( flexible_print, stderr, op, 1, (dump_flags_t)0); + + if ( TREE_CODE ( op) == COMPONENT_REF ) + { + tree field_op = TREE_OPERAND ( op, 1); + tree field_type = TREE_TYPE ( field_op); + tree base_field_type = base_type_of ( field_type); + //DEBUG_A("field_op = "); + //DEBUG_F( flexible_print, stderr, field_op, 1, (dump_flags_t)0); + //DEBUG_A("field_type = "); + //DEBUG_F( flexible_print, stderr, field_type, 1, (dump_flags_t)0); + //DEBUG_A("base_field_type = "); + //DEBUG_F( flexible_print, stderr, base_field_type, 1, (dump_flags_t)0); + return get_reorgtype_info ( base_field_type, info); + } + else + { + tree op_type = TREE_TYPE ( op); + tree op_base_type = base_type_of ( op_type); + //DEBUG_A("op_type = "); + //DEBUG_F( flexible_print, stderr, op_type, 1, (dump_flags_t)0); + //DEBUG_A("op_base_type = "); + //DEBUG_F( flexible_print, stderr, op_base_type, 1, (dump_flags_t)0); + + return get_reorgtype_info ( op_base_type, info); + } } + num_reorgs++; } } gcc_assert ( 0); @@ -2581,6 +2789,22 @@ modify_ssa_name_type ( tree ssa_name, tree type) } } +bool +is_assign_from_ssa ( gimple *stmt ) +{ + if ( is_gimple_assign ( stmt) ) + { + //DEBUG_A("is gimple assign\n"); + if ( gimple_assign_rhs_class ( stmt) == GIMPLE_SINGLE_RHS ) + { + //DEBUG_A("has single rhs\n"); + if ( TREE_CODE ( gimple_assign_rhs1 ( stmt)) == SSA_NAME ) + return true; + } + } + return false; +} + //-- debugging only -- //static const char * #if DEBUGGING @@ -2640,6 +2864,33 @@ type_name_to_str ( tree tn) return identifier_to_locale ( IDENTIFIER_POINTER ( tn)); } +const char * +optrans_to_str ( enum ReorgOpTrans e ) +{ + switch ( e ) + { + case ReorgOpT_Temp: + return "Temp"; + case ReorgOpT_Address: + return "Address"; + case ReorgOpT_Pointer: + return "Pointer"; + case ReorgOpT_Struct: + return "Struct"; + case ReorgOpT_Deref: + return "Deref"; + case ReorgOpT_Array: + return "Array"; + case ReorgOpT_Scalar: + return "Scalar"; + case ReorgOpT_Indirect: + return "Indirect"; + case ReorgOpT_AryDir: + return "AryDir"; + } + return NULL; +} + #if DEBUGGING void handle_debug_indenting ( int amount ) diff --git a/gcc/ipa-structure-reorg.h b/gcc/ipa-structure-reorg.h index 8454c42dd89..0a3a87e3088 100644 --- a/gcc/ipa-structure-reorg.h +++ b/gcc/ipa-structure-reorg.h @@ -28,6 +28,8 @@ along with GCC; see the file COPYING3. If not see #define USE_REORG_TYPES 1 // If PRINT_FORMAT is true use pass specific print format. #define PRINT_FORMAT false +// Trun off actual transformations for testing +#define BYPASS_TRANSFORM false typedef struct RT_Elim RT_Elim; typedef struct RT_Reorder RT_Reorder; @@ -99,7 +101,9 @@ enum ReorgOpTrans { ReorgOpT_Array, // "x[i]" ReorgOpT_Scalar, // "z" ReorgOpT_Indirect, // "a->f" - ReorgOpT_AryDir // "x[i].f" + ReorgOpT_AryDir, // "x[i].f" + ReorgOpT_Cst, + ReorgOpT_Cst0 }; enum CompressionControl { @@ -160,6 +164,7 @@ struct Info { // TODO: What is the meaning of reorg type? // Hasn't this meaning changed now that we have three // transformations roughly running at the same time? + // Eric: Interesting point std::vector <ReorgType_t> *reorg_type; // Added to by remove_deleted_types std::vector <ReorgType_t> *saved_reorg_type; @@ -176,6 +181,7 @@ struct Info { // Debug flags bool show_all_reorg_cands; bool show_all_reorg_cands_in_detail; + bool show_perf_qualify; bool show_prog_decls; bool show_delete; bool show_new_BBs; @@ -196,6 +202,7 @@ struct Info { , reorg_dump_file(NULL) , show_all_reorg_cands(false) , show_all_reorg_cands_in_detail(false) + , show_perf_qualify(false) , show_prog_decls(false) , show_new_BBs(false) , show_transforms(false) @@ -222,13 +229,14 @@ extern int str_reorg_instance_interleave ( Info *); #endif extern int number_of_levels ( tree); +extern tree make_multilevel( tree, int); extern bool modify_decl_core ( tree *, Info *); extern void delete_reorgtype ( ReorgType_t *, Info_t *); extern void undelete_reorgtype ( ReorgType_t *, Info_t *); extern void clear_deleted_types( Info *); extern void restore_deleted_types ( Info *); extern void remove_deleted_types ( Info *, ReorgFn); -extern enum ReorgOpTrans recognize_op ( tree, Info_t *); +extern enum ReorgOpTrans recognize_op ( tree, bool, Info_t *); extern ReorgTransformation reorg_recognize ( gimple *, cgraph_node *, Info_t *); @@ -246,14 +254,16 @@ extern void print_program ( FILE *, bool, int, Info_t *); extern void print_type ( FILE *, tree); extern void modify_ssa_name_type ( tree, tree); extern bool print_internals (gimple *, void *); +extern const char *optrans_to_str ( enum ReorgOpTrans); +extern bool is_assign_from_ssa ( gimple *); -// I have no intention of leaving this or uses of the -// defined marcos in the code. However, some of uses -// should obviously be converted to dump file information. +// I have no intention of leaving these debugging marcos or uses of +// them in the code. However, some of the uses should obviously be +// converted to dump file information. -#define DEBUGGING 0 +#define DEBUGGING 1 #if DEBUGGING enum Display { Show_nothing, |