Mercurial > hg > CbC > CbC_gcc
diff gcc/graphite.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | 84e7813d76e9 |
line wrap: on
line diff
--- a/gcc/graphite.c Sun Aug 21 07:07:55 2011 +0900 +++ b/gcc/graphite.c Fri Oct 27 22:46:09 2017 +0900 @@ -1,5 +1,5 @@ /* Gimple Represented as Polyhedra. - Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 2006-2017 Free Software Foundation, Inc. Contributed by Sebastian Pop <sebastian.pop@inria.fr>. This file is part of GCC. @@ -25,36 +25,39 @@ An early description of this pass can be found in the GCC Summit'06 paper "GRAPHITE: Polyhedral Analyses and Optimizations for GCC". The wiki page http://gcc.gnu.org/wiki/Graphite contains pointers to - the related work. + the related work. */ - One important document to read is CLooG's internal manual: - http://repo.or.cz/w/cloog-ppl.git?a=blob_plain;f=doc/cloog.texi;hb=HEAD - that describes the data structure of loops used in this file, and - the functions that are used for transforming the code. */ +#define USES_ISL #include "config.h" #include "system.h" #include "coretypes.h" +#include "backend.h" #include "diagnostic-core.h" -#include "tree-flow.h" -#include "tree-dump.h" #include "cfgloop.h" -#include "tree-chrec.h" +#include "tree-pass.h" +#include "params.h" +#include "pretty-print.h" + +#ifdef HAVE_isl +#include "cfghooks.h" +#include "tree.h" +#include "gimple.h" +#include "ssa.h" +#include "fold-const.h" +#include "gimple-iterator.h" +#include "tree-cfg.h" +#include "tree-ssa-loop.h" #include "tree-data-ref.h" #include "tree-scalar-evolution.h" -#include "sese.h" #include "dbgcnt.h" - -#ifdef HAVE_cloog - -#include "ppl_c.h" -#include "graphite-ppl.h" -#include "graphite-poly.h" -#include "graphite-scop-detection.h" -#include "graphite-clast-to-gimple.h" -#include "graphite-sese-to-poly.h" - -CloogState *cloog_state; +#include "tree-parloops.h" +#include "tree-cfgcleanup.h" +#include "tree-vectorizer.h" +#include "tree-ssa-loop-manip.h" +#include "tree-ssa.h" +#include "tree-into-ssa.h" +#include "graphite.h" /* Print global statistics to FILE. */ @@ -65,19 +68,20 @@ long n_loops = 0; long n_stmts = 0; long n_conditions = 0; - long n_p_bbs = 0; - long n_p_loops = 0; - long n_p_stmts = 0; - long n_p_conditions = 0; + profile_count n_p_bbs = profile_count::zero (); + profile_count n_p_loops = profile_count::zero (); + profile_count n_p_stmts = profile_count::zero (); + profile_count n_p_conditions = profile_count::zero (); basic_block bb; - FOR_ALL_BB (bb) + FOR_ALL_BB_FN (bb, cfun) { gimple_stmt_iterator psi; n_bbs++; - n_p_bbs += bb->count; + if (bb->count.initialized_p ()) + n_p_bbs += bb->count; /* Ignore artificial surrounding loop. */ if (bb == bb->loop_father->header @@ -87,16 +91,18 @@ n_p_loops += bb->count; } - if (VEC_length (edge, bb->succs) > 1) + if (EDGE_COUNT (bb->succs) > 1) { n_conditions++; - n_p_conditions += bb->count; + if (bb->count.initialized_p ()) + n_p_conditions += bb->count; } for (psi = gsi_start_bb (bb); !gsi_end_p (psi); gsi_next (&psi)) { n_stmts++; - n_p_stmts += bb->count; + if (bb->count.initialized_p ()) + n_p_stmts += bb->count; } } @@ -105,11 +111,16 @@ fprintf (file, "LOOPS:%ld, ", n_loops); fprintf (file, "CONDITIONS:%ld, ", n_conditions); fprintf (file, "STMTS:%ld)\n", n_stmts); - fprintf (file, "\nGlobal profiling statistics ("); - fprintf (file, "BBS:%ld, ", n_p_bbs); - fprintf (file, "LOOPS:%ld, ", n_p_loops); - fprintf (file, "CONDITIONS:%ld, ", n_p_conditions); - fprintf (file, "STMTS:%ld)\n", n_p_stmts); + fprintf (file, "Global profiling statistics ("); + fprintf (file, "BBS:"); + n_p_bbs.dump (file); + fprintf (file, ", LOOPS:"); + n_p_loops.dump (file); + fprintf (file, ", CONDITIONS:"); + n_p_conditions.dump (file); + fprintf (file, ", STMTS:"); + n_p_stmts.dump (file); + fprintf (file, ")\n\n"); } /* Print statistics for SCOP to FILE. */ @@ -121,25 +132,26 @@ long n_loops = 0; long n_stmts = 0; long n_conditions = 0; - long n_p_bbs = 0; - long n_p_loops = 0; - long n_p_stmts = 0; - long n_p_conditions = 0; + profile_count n_p_bbs = profile_count::zero (); + profile_count n_p_loops = profile_count::zero (); + profile_count n_p_stmts = profile_count::zero (); + profile_count n_p_conditions = profile_count::zero (); basic_block bb; - FOR_ALL_BB (bb) + FOR_ALL_BB_FN (bb, cfun) { gimple_stmt_iterator psi; loop_p loop = bb->loop_father; - if (!bb_in_sese_p (bb, SCOP_REGION (scop))) + if (!bb_in_sese_p (bb, scop->scop_info->region)) continue; n_bbs++; - n_p_bbs += bb->count; + if (bb->count.initialized_p ()) + n_p_bbs += bb->count; - if (VEC_length (edge, bb->succs) > 1) + if (EDGE_COUNT (bb->succs) > 1) { n_conditions++; n_p_conditions += bb->count; @@ -151,95 +163,169 @@ n_p_stmts += bb->count; } - if (loop->header == bb && loop_in_sese_p (loop, SCOP_REGION (scop))) + if (loop->header == bb && loop_in_sese_p (loop, scop->scop_info->region)) { n_loops++; n_p_loops += bb->count; } } + fprintf (file, "\nFunction Name: %s\n", current_function_name ()); + + edge scop_begin = scop->scop_info->region.entry; + edge scop_end = scop->scop_info->region.exit; + + fprintf (file, "\nSCoP (entry_edge (bb_%d, bb_%d), ", + scop_begin->src->index, scop_begin->dest->index); + fprintf (file, "exit_edge (bb_%d, bb_%d))", + scop_end->src->index, scop_end->dest->index); + fprintf (file, "\nSCoP statistics ("); fprintf (file, "BBS:%ld, ", n_bbs); fprintf (file, "LOOPS:%ld, ", n_loops); fprintf (file, "CONDITIONS:%ld, ", n_conditions); fprintf (file, "STMTS:%ld)\n", n_stmts); - fprintf (file, "\nSCoP profiling statistics ("); - fprintf (file, "BBS:%ld, ", n_p_bbs); - fprintf (file, "LOOPS:%ld, ", n_p_loops); - fprintf (file, "CONDITIONS:%ld, ", n_p_conditions); - fprintf (file, "STMTS:%ld)\n", n_p_stmts); + fprintf (file, "SCoP profiling statistics ("); + fprintf (file, "BBS:"); + n_p_bbs.dump (file); + fprintf (file, ", LOOPS:"); + n_p_loops.dump (file); + fprintf (file, ", CONDITIONS:"); + n_p_conditions.dump (file); + fprintf (file, ", STMTS:"); + n_p_stmts.dump (file); + fprintf (file, ")\n\n"); } /* Print statistics for SCOPS to FILE. */ static void -print_graphite_statistics (FILE* file, VEC (scop_p, heap) *scops) +print_graphite_statistics (FILE* file, vec<scop_p> scops) { int i; - scop_p scop; - FOR_EACH_VEC_ELT (scop_p, scops, i, scop) + FOR_EACH_VEC_ELT (scops, i, scop) print_graphite_scop_statistics (file, scop); } -/* Initialize graphite: when there are no loops returns false. */ +/* Deletes all scops in SCOPS. */ + +static void +free_scops (vec<scop_p> scops) +{ + int i; + scop_p scop; + + FOR_EACH_VEC_ELT (scops, i, scop) + free_scop (scop); + + scops.release (); +} -static bool -graphite_initialize (void) +/* Transforms LOOP to the canonical loop closed SSA form. */ + +static void +canonicalize_loop_closed_ssa (loop_p loop) { - int ppl_initialized; + edge e = single_exit (loop); + basic_block bb; + gphi_iterator psi; + + if (!e || (e->flags & EDGE_COMPLEX)) + return; + + bb = e->dest; - if (number_of_loops () <= 1 - /* FIXME: This limit on the number of basic blocks of a function - should be removed when the SCOP detection is faster. */ - || n_basic_blocks > PARAM_VALUE (PARAM_GRAPHITE_MAX_BBS_PER_FUNCTION)) + /* Make the loop-close PHI node BB contain only PHIs and have a + single predecessor. */ + if (single_pred_p (bb)) + { + e = split_block_after_labels (bb); + bb = e->src; + } + else { - if (dump_file && (dump_flags & TDF_DETAILS)) - print_global_statistics (dump_file); + basic_block close = split_edge (e); + e = single_succ_edge (close); + for (psi = gsi_start_phis (bb); !gsi_end_p (psi); gsi_next (&psi)) + { + gphi *phi = psi.phi (); + use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e); + tree arg = USE_FROM_PTR (use_p); - return false; + /* Only add close phi nodes for SSA_NAMEs defined in LOOP. */ + if (TREE_CODE (arg) != SSA_NAME + || SSA_NAME_IS_DEFAULT_DEF (arg) + || ! flow_bb_inside_loop_p (loop, + gimple_bb (SSA_NAME_DEF_STMT (arg)))) + continue; + + tree res = copy_ssa_name (arg); + gphi *close_phi = create_phi_node (res, close); + add_phi_arg (close_phi, arg, gimple_phi_arg_edge (close_phi, 0), + UNKNOWN_LOCATION); + SET_USE (use_p, res); + } + bb = close; } - scev_reset (); - recompute_all_dominators (); - initialize_original_copy_tables (); + /* Eliminate duplicates. This relies on processing loops from + innermost to outer. */ + for (psi = gsi_start_phis (bb); !gsi_end_p (psi); gsi_next (&psi)) + { + gphi_iterator gsi = psi; + gphi *phi = psi.phi (); - ppl_initialized = ppl_initialize (); - gcc_assert (ppl_initialized == 0); + /* At this point, PHI should be a close phi in normal form. */ + gcc_assert (gimple_phi_num_args (phi) == 1); - cloog_state = cloog_state_malloc (); - cloog_initialize (); - - if (dump_file && dump_flags) - dump_function_to_file (current_function_decl, dump_file, dump_flags); - - return true; + /* Iterate over the next phis and remove duplicates. */ + gsi_next (&gsi); + while (!gsi_end_p (gsi)) + if (gimple_phi_arg_def (phi, 0) == gimple_phi_arg_def (gsi.phi (), 0)) + { + replace_uses_by (gimple_phi_result (gsi.phi ()), + gimple_phi_result (phi)); + remove_phi_node (&gsi, true); + } + else + gsi_next (&gsi); + } } -/* Finalize graphite: perform CFG cleanup when NEED_CFG_CLEANUP_P is - true. */ +/* Converts the current loop closed SSA form to a canonical form + expected by the Graphite code generation. + + The loop closed SSA form has the following invariant: a variable + defined in a loop that is used outside the loop appears only in the + phi nodes in the destination of the loop exit. These phi nodes are + called close phi nodes. + + The canonical loop closed SSA form contains the extra invariants: + + - when the loop contains only one exit, the close phi nodes contain + only one argument. That implies that the basic block that contains + the close phi nodes has only one predecessor, that is a basic block + in the loop. + + - the basic block containing the close phi nodes does not contain + other statements. + + - there exist only one phi node per definition in the loop. +*/ static void -graphite_finalize (bool need_cfg_cleanup_p) +canonicalize_loop_closed_ssa_form (void) { - if (need_cfg_cleanup_p) - { - scev_reset (); - cleanup_tree_cfg (); - profile_status = PROFILE_ABSENT; - release_recorded_exits (); - tree_estimate_probability (); - } + loop_p loop; + FOR_EACH_LOOP (loop, LI_FROM_INNERMOST) + canonicalize_loop_closed_ssa (loop); - cloog_state_free (cloog_state); - cloog_finalize (); - ppl_finalize (); - free_original_copy_tables (); + checking_verify_loop_closed_ssa (true); +} - if (dump_file && dump_flags) - print_loops (dump_file, 3); -} +isl_ctx *the_isl_ctx; /* Perform a set of linear transforms on the loops of the current function. */ @@ -249,14 +335,34 @@ { int i; scop_p scop; - bool need_cfg_cleanup_p = false; - VEC (scop_p, heap) *scops = NULL; - htab_t bb_pbb_mapping; + bool changed = false; + vec<scop_p> scops = vNULL; + isl_ctx *ctx; - if (!graphite_initialize ()) + /* If a function is parallel it was most probably already run through graphite + once. No need to run again. */ + if (parallelized_function_p (cfun->decl)) return; + calculate_dominance_info (CDI_DOMINATORS); + + ctx = isl_ctx_alloc (); + isl_options_set_on_error (ctx, ISL_ON_ERROR_ABORT); + the_isl_ctx = ctx; + + sort_sibling_loops (cfun); + canonicalize_loop_closed_ssa_form (); + + /* Print the loop structure. */ + if (dump_file && (dump_flags & TDF_DETAILS)) + { + print_loops (dump_file, 2); + print_loops (dump_file, 3); + } + + calculate_dominance_info (CDI_POST_DOMINATORS); build_scops (&scops); + free_dominance_info (CDI_POST_DOMINATORS); if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -264,30 +370,167 @@ print_global_statistics (dump_file); } - bb_pbb_mapping = htab_create (10, bb_pbb_map_hash, eq_bb_pbb_map, free); - - FOR_EACH_VEC_ELT (scop_p, scops, i, scop) + FOR_EACH_VEC_ELT (scops, i, scop) if (dbg_cnt (graphite_scop)) { - build_poly_scop (scop); + scop->isl_context = ctx; + if (!build_poly_scop (scop)) + continue; + + if (!apply_poly_transforms (scop)) + continue; - if (POLY_SCOP_P (scop) - && apply_poly_transforms (scop) - && gloog (scop, bb_pbb_mapping)) - need_cfg_cleanup_p = true; + changed = true; + if (graphite_regenerate_ast_isl (scop)) + { + location_t loc = find_loop_location + (scops[i]->scop_info->region.entry->dest->loop_father); + dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, + "loop nest optimized\n"); + } } - htab_delete (bb_pbb_mapping); + if (changed) + { + mark_virtual_operands_for_renaming (cfun); + update_ssa (TODO_update_ssa); + checking_verify_ssa (true, true); + rewrite_into_loop_closed_ssa (NULL, 0); + scev_reset (); + checking_verify_loop_structure (); + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + loop_p loop; + int num_no_dependency = 0; + + FOR_EACH_LOOP (loop, 0) + if (loop->can_be_parallel) + num_no_dependency++; + + fprintf (dump_file, "%d loops carried no dependency.\n", + num_no_dependency); + } + free_scops (scops); - graphite_finalize (need_cfg_cleanup_p); + the_isl_ctx = NULL; + isl_ctx_free (ctx); + + if (changed) + { + cleanup_tree_cfg (); + profile_status_for_fn (cfun) = PROFILE_ABSENT; + release_recorded_exits (cfun); + tree_estimate_probability (false); + } + } -#else /* If Cloog is not available: #ifndef HAVE_cloog. */ +#else /* If isl is not available: #ifndef HAVE_isl. */ -void +static void graphite_transform_loops (void) { - sorry ("Graphite loop optimizations cannot be used"); + sorry ("Graphite loop optimizations cannot be used (isl is not available)."); } #endif + + +static unsigned int +graphite_transforms (struct function *fun) +{ + if (number_of_loops (fun) <= 1) + return 0; + + graphite_transform_loops (); + + return 0; +} + +static bool +gate_graphite_transforms (void) +{ + /* Enable -fgraphite pass if any one of the graphite optimization flags + is turned on. */ + if (flag_graphite_identity + || flag_loop_parallelize_all + || flag_loop_nest_optimize) + flag_graphite = 1; + + return flag_graphite != 0; +} + +namespace { + +const pass_data pass_data_graphite = +{ + GIMPLE_PASS, /* type */ + "graphite0", /* name */ + OPTGROUP_LOOP, /* optinfo_flags */ + TV_GRAPHITE, /* tv_id */ + ( PROP_cfg | PROP_ssa ), /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_graphite : public gimple_opt_pass +{ +public: + pass_graphite (gcc::context *ctxt) + : gimple_opt_pass (pass_data_graphite, ctxt) + {} + + /* opt_pass methods: */ + virtual bool gate (function *) { return gate_graphite_transforms (); } + +}; // class pass_graphite + +} // anon namespace + +gimple_opt_pass * +make_pass_graphite (gcc::context *ctxt) +{ + return new pass_graphite (ctxt); +} + +namespace { + +const pass_data pass_data_graphite_transforms = +{ + GIMPLE_PASS, /* type */ + "graphite", /* name */ + OPTGROUP_LOOP, /* optinfo_flags */ + TV_GRAPHITE_TRANSFORMS, /* tv_id */ + ( PROP_cfg | PROP_ssa ), /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_graphite_transforms : public gimple_opt_pass +{ +public: + pass_graphite_transforms (gcc::context *ctxt) + : gimple_opt_pass (pass_data_graphite_transforms, ctxt) + {} + + /* opt_pass methods: */ + virtual bool gate (function *) { return gate_graphite_transforms (); } + virtual unsigned int execute (function *fun) { return graphite_transforms (fun); } + +}; // class pass_graphite_transforms + +} // anon namespace + +gimple_opt_pass * +make_pass_graphite_transforms (gcc::context *ctxt) +{ + return new pass_graphite_transforms (ctxt); +} + +