diff options
author | Ian Lance Taylor <iant@golang.org> | 2022-02-11 15:02:44 -0800 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2022-02-11 15:02:44 -0800 |
commit | 9a510fb0970d3d9a4201bce8965cabe67850386b (patch) | |
tree | 43d7fd2bbfd7ad8c9625a718a5e8718889351994 /gcc/graphite-scop-detection.c | |
parent | a6d3012b274f38b20e2a57162106f625746af6c6 (diff) | |
parent | 8dc2499aa62f768c6395c9754b8cabc1ce25c494 (diff) | |
download | gcc-9a510fb0970d3d9a4201bce8965cabe67850386b.zip gcc-9a510fb0970d3d9a4201bce8965cabe67850386b.tar.gz gcc-9a510fb0970d3d9a4201bce8965cabe67850386b.tar.bz2 |
Merge from trunk revision 8dc2499aa62f768c6395c9754b8cabc1ce25c494
Diffstat (limited to 'gcc/graphite-scop-detection.c')
-rw-r--r-- | gcc/graphite-scop-detection.c | 1671 |
1 files changed, 0 insertions, 1671 deletions
diff --git a/gcc/graphite-scop-detection.c b/gcc/graphite-scop-detection.c deleted file mode 100644 index 3e729b1..0000000 --- a/gcc/graphite-scop-detection.c +++ /dev/null @@ -1,1671 +0,0 @@ -/* Detection of Static Control Parts (SCoP) for Graphite. - Copyright (C) 2009-2021 Free Software Foundation, Inc. - Contributed by Sebastian Pop <sebastian.pop@amd.com> and - Tobias Grosser <grosser@fim.uni-passau.de>. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -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/>. */ - -#define INCLUDE_ISL - -#include "config.h" - -#ifdef HAVE_isl - -#include "system.h" -#include "coretypes.h" -#include "backend.h" -#include "cfghooks.h" -#include "domwalk.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-manip.h" -#include "tree-ssa-loop-niter.h" -#include "tree-ssa-loop.h" -#include "tree-into-ssa.h" -#include "tree-ssa.h" -#include "cfgloop.h" -#include "tree-data-ref.h" -#include "tree-scalar-evolution.h" -#include "tree-pass.h" -#include "tree-ssa-propagate.h" -#include "gimple-pretty-print.h" -#include "cfganal.h" -#include "graphite.h" - -class debug_printer -{ -private: - FILE *dump_file; - -public: - void - set_dump_file (FILE *f) - { - gcc_assert (f); - dump_file = f; - } - - friend debug_printer & - operator<< (debug_printer &output, int i) - { - fprintf (output.dump_file, "%d", i); - return output; - } - friend debug_printer & - operator<< (debug_printer &output, const char *s) - { - fprintf (output.dump_file, "%s", s); - return output; - } -} dp; - -#define DEBUG_PRINT(args) do \ - { \ - if (dump_file && (dump_flags & TDF_DETAILS)) { args; } \ - } while (0) - -/* Pretty print to FILE all the SCoPs in DOT format and mark them with - different colors. If there are not enough colors, paint the - remaining SCoPs in gray. - - Special nodes: - - "*" after the node number denotes the entry of a SCoP, - - "#" after the node number denotes the exit of a SCoP, - - "()" around the node number denotes the entry or the - exit nodes of the SCOP. These are not part of SCoP. */ - -DEBUG_FUNCTION void -dot_all_sese (FILE *file, vec<sese_l>& scops) -{ - /* Disable debugging while printing graph. */ - dump_flags_t tmp_dump_flags = dump_flags; - dump_flags = TDF_NONE; - - fprintf (file, "digraph all {\n"); - - basic_block bb; - FOR_ALL_BB_FN (bb, cfun) - { - int part_of_scop = false; - - /* Use HTML for every bb label. So we are able to print bbs - which are part of two different SCoPs, with two different - background colors. */ - fprintf (file, "%d [label=<\n <TABLE BORDER=\"0\" CELLBORDER=\"1\" ", - bb->index); - fprintf (file, "CELLSPACING=\"0\">\n"); - - /* Select color for SCoP. */ - sese_l *region; - int i; - FOR_EACH_VEC_ELT (scops, i, region) - { - bool sese_in_region = bb_in_sese_p (bb, *region); - if (sese_in_region || (region->exit->dest == bb) - || (region->entry->dest == bb)) - { - const char *color; - switch (i % 17) - { - case 0: /* red */ - color = "#e41a1c"; - break; - case 1: /* blue */ - color = "#377eb8"; - break; - case 2: /* green */ - color = "#4daf4a"; - break; - case 3: /* purple */ - color = "#984ea3"; - break; - case 4: /* orange */ - color = "#ff7f00"; - break; - case 5: /* yellow */ - color = "#ffff33"; - break; - case 6: /* brown */ - color = "#a65628"; - break; - case 7: /* rose */ - color = "#f781bf"; - break; - case 8: - color = "#8dd3c7"; - break; - case 9: - color = "#ffffb3"; - break; - case 10: - color = "#bebada"; - break; - case 11: - color = "#fb8072"; - break; - case 12: - color = "#80b1d3"; - break; - case 13: - color = "#fdb462"; - break; - case 14: - color = "#b3de69"; - break; - case 15: - color = "#fccde5"; - break; - case 16: - color = "#bc80bd"; - break; - default: /* gray */ - color = "#999999"; - } - - fprintf (file, " <TR><TD WIDTH=\"50\" BGCOLOR=\"%s\">", - color); - - if (!sese_in_region) - fprintf (file, " ("); - - if (bb == region->entry->dest && bb == region->exit->dest) - fprintf (file, " %d*# ", bb->index); - else if (bb == region->entry->dest) - fprintf (file, " %d* ", bb->index); - else if (bb == region->exit->dest) - fprintf (file, " %d# ", bb->index); - else - fprintf (file, " %d ", bb->index); - - fprintf (file, "{lp_%d}", bb->loop_father->num); - - if (!sese_in_region) - fprintf (file, ")"); - - fprintf (file, "</TD></TR>\n"); - part_of_scop = true; - } - } - - if (!part_of_scop) - { - fprintf (file, " <TR><TD WIDTH=\"50\" BGCOLOR=\"#ffffff\">"); - fprintf (file, " %d {lp_%d} </TD></TR>\n", bb->index, - bb->loop_father->num); - } - fprintf (file, " </TABLE>>, shape=box, style=\"setlinewidth(0)\"]\n"); - } - - FOR_ALL_BB_FN (bb, cfun) - { - edge e; - edge_iterator ei; - FOR_EACH_EDGE (e, ei, bb->succs) - fprintf (file, "%d -> %d;\n", bb->index, e->dest->index); - } - - fputs ("}\n\n", file); - - /* Enable debugging again. */ - dump_flags = tmp_dump_flags; -} - -/* Display SCoP on stderr. */ - -DEBUG_FUNCTION void -dot_sese (sese_l& scop) -{ - vec<sese_l> scops; - scops.create (1); - - if (scop) - scops.safe_push (scop); - - dot_all_sese (stderr, scops); - - scops.release (); -} - -DEBUG_FUNCTION void -dot_cfg () -{ - vec<sese_l> scops; - scops.create (1); - dot_all_sese (stderr, scops); - scops.release (); -} - -/* Returns a COND_EXPR statement when BB has a single predecessor, the - edge between BB and its predecessor is not a loop exit edge, and - the last statement of the single predecessor is a COND_EXPR. */ - -static gcond * -single_pred_cond_non_loop_exit (basic_block bb) -{ - if (single_pred_p (bb)) - { - edge e = single_pred_edge (bb); - basic_block pred = e->src; - gimple *stmt; - - if (loop_depth (pred->loop_father) > loop_depth (bb->loop_father)) - return NULL; - - stmt = last_stmt (pred); - - if (stmt && gimple_code (stmt) == GIMPLE_COND) - return as_a<gcond *> (stmt); - } - - return NULL; -} - -namespace -{ - -/* Build the maximal scop containing LOOPs and add it to SCOPS. */ - -class scop_detection -{ -public: - scop_detection () : scops (vNULL) {} - - ~scop_detection () - { - scops.release (); - } - - /* A marker for invalid sese_l. */ - static sese_l invalid_sese; - - /* Return the SCOPS in this SCOP_DETECTION. */ - - vec<sese_l> - get_scops () - { - return scops; - } - - /* Return an sese_l around the LOOP. */ - - sese_l get_sese (loop_p loop); - - /* Merge scops at same loop depth and returns the new sese. - Returns a new SESE when merge was successful, INVALID_SESE otherwise. */ - - sese_l merge_sese (sese_l first, sese_l second) const; - - /* Build scop outer->inner if possible. */ - - void build_scop_depth (loop_p loop); - - /* Return true when BEGIN is the preheader edge of a loop with a single exit - END. */ - - static bool region_has_one_loop (sese_l s); - - /* Add to SCOPS a scop starting at SCOP_BEGIN and ending at SCOP_END. */ - - void add_scop (sese_l s); - - /* Returns true if S1 subsumes/surrounds S2. */ - static bool subsumes (sese_l s1, sese_l s2); - - /* Remove a SCoP which is subsumed by S1. */ - void remove_subscops (sese_l s1); - - /* Returns true if S1 intersects with S2. Since we already know that S1 does - not subsume S2 or vice-versa, we only check for entry bbs. */ - - static bool intersects (sese_l s1, sese_l s2); - - /* Remove one of the scops when it intersects with any other. */ - - void remove_intersecting_scops (sese_l s1); - - /* Return true when a statement in SCOP cannot be represented by Graphite. */ - - bool harmful_loop_in_region (sese_l scop) const; - - /* Return true only when STMT is simple enough for being handled by Graphite. - This depends on SCOP, as the parameters are initialized relatively to - this basic block, the linear functions are initialized based on the - outermost loop containing STMT inside the SCOP. BB is the place where we - try to evaluate the STMT. */ - - bool stmt_simple_for_scop_p (sese_l scop, gimple *stmt, - basic_block bb) const; - - /* Something like "n * m" is not allowed. */ - - static bool graphite_can_represent_init (tree e); - - /* Return true when SCEV can be represented in the polyhedral model. - - An expression can be represented, if it can be expressed as an - affine expression. For loops (i, j) and parameters (m, n) all - affine expressions are of the form: - - x1 * i + x2 * j + x3 * m + x4 * n + x5 * 1 where x1..x5 element of Z - - 1 i + 20 j + (-2) m + 25 - - Something like "i * n" or "n * m" is not allowed. */ - - static bool graphite_can_represent_scev (sese_l scop, tree scev); - - /* Return true when EXPR can be represented in the polyhedral model. - - This means an expression can be represented, if it is linear with respect - to the loops and the strides are non parametric. LOOP is the place where - the expr will be evaluated. SCOP defines the region we analyse. */ - - static bool graphite_can_represent_expr (sese_l scop, loop_p loop, - tree expr); - - /* Return true if the data references of STMT can be represented by Graphite. - We try to analyze the data references in a loop contained in the SCOP. */ - - static bool stmt_has_simple_data_refs_p (sese_l scop, gimple *stmt); - - /* Remove the close phi node at GSI and replace its rhs with the rhs - of PHI. */ - - static void remove_duplicate_close_phi (gphi *phi, gphi_iterator *gsi); - - /* Returns true when Graphite can represent LOOP in SCOP. - FIXME: For the moment, graphite cannot be used on loops that iterate using - induction variables that wrap. */ - - static bool can_represent_loop (loop_p loop, sese_l scop); - - /* Returns the number of pbbs that are in loops contained in SCOP. */ - - static int nb_pbbs_in_loops (scop_p scop); - -private: - vec<sese_l> scops; -}; - -sese_l scop_detection::invalid_sese (NULL, NULL); - -/* Return an sese_l around the LOOP. */ - -sese_l -scop_detection::get_sese (loop_p loop) -{ - if (!loop) - return invalid_sese; - - edge scop_begin = loop_preheader_edge (loop); - edge scop_end = single_exit (loop); - if (!scop_end || (scop_end->flags & (EDGE_COMPLEX|EDGE_FAKE))) - return invalid_sese; - - return sese_l (scop_begin, scop_end); -} - -/* Merge scops at same loop depth and returns the new sese. - Returns a new SESE when merge was successful, INVALID_SESE otherwise. */ - -sese_l -scop_detection::merge_sese (sese_l first, sese_l second) const -{ - /* In the trivial case first/second may be NULL. */ - if (!first) - return second; - if (!second) - return first; - - DEBUG_PRINT (dp << "[scop-detection] try merging sese s1: "; - print_sese (dump_file, first); - dp << "[scop-detection] try merging sese s2: "; - print_sese (dump_file, second)); - - auto_bitmap worklist, in_sese_region; - bitmap_set_bit (worklist, get_entry_bb (first)->index); - bitmap_set_bit (worklist, get_exit_bb (first)->index); - bitmap_set_bit (worklist, get_entry_bb (second)->index); - bitmap_set_bit (worklist, get_exit_bb (second)->index); - edge entry = NULL, exit = NULL; - - /* We can optimize the case of adding a loop entry dest or exit - src to the worklist (for single-exit loops) by skipping - directly to the exit dest / entry src. in_sese_region - doesn't have to cover all blocks in the region but merely - its border it acts more like a visited bitmap. */ - do - { - int index = bitmap_first_set_bit (worklist); - bitmap_clear_bit (worklist, index); - basic_block bb = BASIC_BLOCK_FOR_FN (cfun, index); - edge_iterator ei; - edge e; - - /* With fake exit edges we can end up with no possible exit. */ - if (index == EXIT_BLOCK) - { - DEBUG_PRINT (dp << "[scop-detection-fail] cannot merge seses.\n"); - return invalid_sese; - } - - bitmap_set_bit (in_sese_region, bb->index); - - basic_block dom = get_immediate_dominator (CDI_DOMINATORS, bb); - FOR_EACH_EDGE (e, ei, bb->preds) - if (e->src == dom - && (! entry - || dominated_by_p (CDI_DOMINATORS, entry->dest, bb))) - { - if (entry - && ! bitmap_bit_p (in_sese_region, entry->src->index)) - bitmap_set_bit (worklist, entry->src->index); - entry = e; - } - else if (! bitmap_bit_p (in_sese_region, e->src->index)) - bitmap_set_bit (worklist, e->src->index); - - basic_block pdom = get_immediate_dominator (CDI_POST_DOMINATORS, bb); - FOR_EACH_EDGE (e, ei, bb->succs) - if (e->dest == pdom - && (! exit - || dominated_by_p (CDI_POST_DOMINATORS, exit->src, bb))) - { - if (exit - && ! bitmap_bit_p (in_sese_region, exit->dest->index)) - bitmap_set_bit (worklist, exit->dest->index); - exit = e; - } - else if (! bitmap_bit_p (in_sese_region, e->dest->index)) - bitmap_set_bit (worklist, e->dest->index); - } - while (! bitmap_empty_p (worklist)); - - sese_l combined (entry, exit); - - DEBUG_PRINT (dp << "[merged-sese] s1: "; print_sese (dump_file, combined)); - - return combined; -} - -/* Build scop outer->inner if possible. */ - -void -scop_detection::build_scop_depth (loop_p loop) -{ - sese_l s = invalid_sese; - loop = loop->inner; - while (loop) - { - sese_l next = get_sese (loop); - if (! next - || harmful_loop_in_region (next)) - { - if (s) - add_scop (s); - build_scop_depth (loop); - s = invalid_sese; - } - else if (! s) - s = next; - else - { - sese_l combined = merge_sese (s, next); - if (! combined - || harmful_loop_in_region (combined)) - { - add_scop (s); - s = next; - } - else - s = combined; - } - loop = loop->next; - } - if (s) - add_scop (s); -} - -/* Returns true when Graphite can represent LOOP in SCOP. - FIXME: For the moment, graphite cannot be used on loops that iterate using - induction variables that wrap. */ - -bool -scop_detection::can_represent_loop (loop_p loop, sese_l scop) -{ - tree niter; - struct tree_niter_desc niter_desc; - - /* We can only handle do {} while () style loops correctly. */ - edge exit = single_exit (loop); - if (!exit - || !single_pred_p (loop->latch) - || exit->src != single_pred (loop->latch) - || !empty_block_p (loop->latch)) - return false; - - return !(loop_preheader_edge (loop)->flags & EDGE_IRREDUCIBLE_LOOP) - && number_of_iterations_exit (loop, single_exit (loop), &niter_desc, false) - && niter_desc.control.no_overflow - && (niter = number_of_latch_executions (loop)) - && !chrec_contains_undetermined (niter) - && graphite_can_represent_expr (scop, loop, niter); -} - -/* Return true when BEGIN is the preheader edge of a loop with a single exit - END. */ - -bool -scop_detection::region_has_one_loop (sese_l s) -{ - edge begin = s.entry; - edge end = s.exit; - /* Check for a single perfectly nested loop. */ - if (begin->dest->loop_father->inner) - return false; - - /* Otherwise, check whether we have adjacent loops. */ - return (single_pred_p (end->src) - && begin->dest->loop_father == single_pred (end->src)->loop_father); -} - -/* Add to SCOPS a scop starting at SCOP_BEGIN and ending at SCOP_END. */ - -void -scop_detection::add_scop (sese_l s) -{ - gcc_assert (s); - - /* If the exit edge is fake discard the SCoP for now as we're removing the - fake edges again after analysis. */ - if (s.exit->flags & EDGE_FAKE) - { - DEBUG_PRINT (dp << "[scop-detection-fail] Discarding infinite loop SCoP: "; - print_sese (dump_file, s)); - return; - } - - /* Include the BB with the loop-closed SSA PHI nodes, we need this - block in the region for code-generating out-of-SSA copies. - canonicalize_loop_closed_ssa makes sure that is in proper shape. */ - if (s.exit->dest != EXIT_BLOCK_PTR_FOR_FN (cfun) - && loop_exit_edge_p (s.exit->src->loop_father, s.exit)) - { - gcc_assert (single_pred_p (s.exit->dest) - && single_succ_p (s.exit->dest) - && sese_trivially_empty_bb_p (s.exit->dest)); - s.exit = single_succ_edge (s.exit->dest); - } - - /* Do not add scops with only one loop. */ - if (region_has_one_loop (s)) - { - DEBUG_PRINT (dp << "[scop-detection-fail] Discarding one loop SCoP: "; - print_sese (dump_file, s)); - return; - } - - if (get_exit_bb (s) == EXIT_BLOCK_PTR_FOR_FN (cfun)) - { - DEBUG_PRINT (dp << "[scop-detection-fail] " - << "Discarding SCoP exiting to return: "; - print_sese (dump_file, s)); - return; - } - - /* Remove all the scops which are subsumed by s. */ - remove_subscops (s); - - /* Remove intersecting scops. FIXME: It will be a good idea to keep - the non-intersecting part of the scop already in the list. */ - remove_intersecting_scops (s); - - scops.safe_push (s); - DEBUG_PRINT (dp << "[scop-detection] Adding SCoP: "; print_sese (dump_file, s)); -} - -/* Return true when a statement in SCOP cannot be represented by Graphite. */ - -bool -scop_detection::harmful_loop_in_region (sese_l scop) const -{ - basic_block exit_bb = get_exit_bb (scop); - basic_block entry_bb = get_entry_bb (scop); - - DEBUG_PRINT (dp << "[checking-harmful-bbs] "; - print_sese (dump_file, scop)); - gcc_assert (dominated_by_p (CDI_DOMINATORS, exit_bb, entry_bb)); - - auto_vec<basic_block> worklist; - auto_bitmap loops; - - worklist.safe_push (entry_bb); - while (! worklist.is_empty ()) - { - basic_block bb = worklist.pop (); - DEBUG_PRINT (dp << "Visiting bb_" << bb->index << "\n"); - - /* The basic block should not be part of an irreducible loop. */ - if (bb->flags & BB_IRREDUCIBLE_LOOP) - return true; - - /* Check for unstructured control flow: CFG not generated by structured - if-then-else. */ - if (bb->succs->length () > 1) - { - edge e; - edge_iterator ei; - FOR_EACH_EDGE (e, ei, bb->succs) - if (!dominated_by_p (CDI_POST_DOMINATORS, bb, e->dest) - && !dominated_by_p (CDI_DOMINATORS, e->dest, bb)) - return true; - } - - /* Collect all loops in the current region. */ - loop_p loop = bb->loop_father; - if (loop_in_sese_p (loop, scop)) - bitmap_set_bit (loops, loop->num); - - /* Check for harmful statements in basic blocks part of the region. */ - for (gimple_stmt_iterator gsi = gsi_start_bb (bb); - !gsi_end_p (gsi); gsi_next (&gsi)) - if (!stmt_simple_for_scop_p (scop, gsi_stmt (gsi), bb)) - return true; - - for (basic_block dom = first_dom_son (CDI_DOMINATORS, bb); - dom; - dom = next_dom_son (CDI_DOMINATORS, dom)) - if (dom != scop.exit->dest) - worklist.safe_push (dom); - } - - /* Go through all loops and check that they are still valid in the combined - scop. */ - unsigned j; - bitmap_iterator bi; - EXECUTE_IF_SET_IN_BITMAP (loops, 0, j, bi) - { - loop_p loop = (*current_loops->larray)[j]; - gcc_assert (loop->num == (int) j); - - /* Check if the loop nests are to be optimized for speed. */ - if (! loop->inner - && ! optimize_loop_for_speed_p (loop)) - { - DEBUG_PRINT (dp << "[scop-detection-fail] loop_" - << loop->num << " is not on a hot path.\n"); - return true; - } - - if (! can_represent_loop (loop, scop)) - { - DEBUG_PRINT (dp << "[scop-detection-fail] cannot represent loop_" - << loop->num << "\n"); - return true; - } - - /* Check if all loop nests have at least one data reference. - ??? This check is expensive and loops premature at this point. - If important to retain we can pre-compute this for all innermost - loops and reject those when we build a SESE region for a loop - during SESE discovery. */ - if (! loop->inner - && ! loop_nest_has_data_refs (loop)) - { - DEBUG_PRINT (dp << "[scop-detection-fail] loop_" << loop->num - << "does not have any data reference.\n"); - return true; - } - } - - return false; -} - -/* Returns true if S1 subsumes/surrounds S2. */ -bool -scop_detection::subsumes (sese_l s1, sese_l s2) -{ - if (dominated_by_p (CDI_DOMINATORS, get_entry_bb (s2), - get_entry_bb (s1)) - && dominated_by_p (CDI_POST_DOMINATORS, s2.exit->dest, - s1.exit->dest)) - return true; - return false; -} - -/* Remove a SCoP which is subsumed by S1. */ -void -scop_detection::remove_subscops (sese_l s1) -{ - int j; - sese_l *s2; - FOR_EACH_VEC_ELT_REVERSE (scops, j, s2) - { - if (subsumes (s1, *s2)) - { - DEBUG_PRINT (dp << "Removing sub-SCoP"; - print_sese (dump_file, *s2)); - scops.unordered_remove (j); - } - } -} - -/* Returns true if S1 intersects with S2. Since we already know that S1 does - not subsume S2 or vice-versa, we only check for entry bbs. */ - -bool -scop_detection::intersects (sese_l s1, sese_l s2) -{ - if (dominated_by_p (CDI_DOMINATORS, get_entry_bb (s2), - get_entry_bb (s1)) - && !dominated_by_p (CDI_DOMINATORS, get_entry_bb (s2), - get_exit_bb (s1))) - return true; - if ((s1.exit == s2.entry) || (s2.exit == s1.entry)) - return true; - - return false; -} - -/* Remove one of the scops when it intersects with any other. */ - -void -scop_detection::remove_intersecting_scops (sese_l s1) -{ - int j; - sese_l *s2; - FOR_EACH_VEC_ELT_REVERSE (scops, j, s2) - { - if (intersects (s1, *s2)) - { - DEBUG_PRINT (dp << "Removing intersecting SCoP"; - print_sese (dump_file, *s2); - dp << "Intersects with:"; - print_sese (dump_file, s1)); - scops.unordered_remove (j); - } - } -} - -/* Something like "n * m" is not allowed. */ - -bool -scop_detection::graphite_can_represent_init (tree e) -{ - switch (TREE_CODE (e)) - { - case POLYNOMIAL_CHREC: - return graphite_can_represent_init (CHREC_LEFT (e)) - && graphite_can_represent_init (CHREC_RIGHT (e)); - - case MULT_EXPR: - if (chrec_contains_symbols (TREE_OPERAND (e, 0))) - return graphite_can_represent_init (TREE_OPERAND (e, 0)) - && tree_fits_shwi_p (TREE_OPERAND (e, 1)); - else - return graphite_can_represent_init (TREE_OPERAND (e, 1)) - && tree_fits_shwi_p (TREE_OPERAND (e, 0)); - - case PLUS_EXPR: - case POINTER_PLUS_EXPR: - case MINUS_EXPR: - return graphite_can_represent_init (TREE_OPERAND (e, 0)) - && graphite_can_represent_init (TREE_OPERAND (e, 1)); - - case NEGATE_EXPR: - case BIT_NOT_EXPR: - CASE_CONVERT: - case NON_LVALUE_EXPR: - return graphite_can_represent_init (TREE_OPERAND (e, 0)); - - default: - break; - } - - return true; -} - -/* Return true when SCEV can be represented in the polyhedral model. - - An expression can be represented, if it can be expressed as an - affine expression. For loops (i, j) and parameters (m, n) all - affine expressions are of the form: - - x1 * i + x2 * j + x3 * m + x4 * n + x5 * 1 where x1..x5 element of Z - - 1 i + 20 j + (-2) m + 25 - - Something like "i * n" or "n * m" is not allowed. */ - -bool -scop_detection::graphite_can_represent_scev (sese_l scop, tree scev) -{ - if (chrec_contains_undetermined (scev)) - return false; - - switch (TREE_CODE (scev)) - { - case NEGATE_EXPR: - case BIT_NOT_EXPR: - CASE_CONVERT: - case NON_LVALUE_EXPR: - return graphite_can_represent_scev (scop, TREE_OPERAND (scev, 0)); - - case PLUS_EXPR: - case POINTER_PLUS_EXPR: - case MINUS_EXPR: - return graphite_can_represent_scev (scop, TREE_OPERAND (scev, 0)) - && graphite_can_represent_scev (scop, TREE_OPERAND (scev, 1)); - - case MULT_EXPR: - return !CONVERT_EXPR_CODE_P (TREE_CODE (TREE_OPERAND (scev, 0))) - && !CONVERT_EXPR_CODE_P (TREE_CODE (TREE_OPERAND (scev, 1))) - && !(chrec_contains_symbols (TREE_OPERAND (scev, 0)) - && chrec_contains_symbols (TREE_OPERAND (scev, 1))) - && graphite_can_represent_init (scev) - && graphite_can_represent_scev (scop, TREE_OPERAND (scev, 0)) - && graphite_can_represent_scev (scop, TREE_OPERAND (scev, 1)); - - case POLYNOMIAL_CHREC: - /* Check for constant strides. With a non constant stride of - 'n' we would have a value of 'iv * n'. Also check that the - initial value can represented: for example 'n * m' cannot be - represented. */ - gcc_assert (loop_in_sese_p (get_loop (cfun, - CHREC_VARIABLE (scev)), scop)); - if (!evolution_function_right_is_integer_cst (scev) - || !graphite_can_represent_init (scev)) - return false; - return graphite_can_represent_scev (scop, CHREC_LEFT (scev)); - - case ADDR_EXPR: - /* We cannot encode addresses for ISL. */ - return false; - - default: - break; - } - - /* Only affine functions can be represented. */ - if (tree_contains_chrecs (scev, NULL) || !scev_is_linear_expression (scev)) - return false; - - return true; -} - -/* Return true when EXPR can be represented in the polyhedral model. - - This means an expression can be represented, if it is linear with respect to - the loops and the strides are non parametric. LOOP is the place where the - expr will be evaluated. SCOP defines the region we analyse. */ - -bool -scop_detection::graphite_can_represent_expr (sese_l scop, loop_p loop, - tree expr) -{ - tree scev = cached_scalar_evolution_in_region (scop, loop, expr); - return graphite_can_represent_scev (scop, scev); -} - -/* Return true if the data references of STMT can be represented by Graphite. - We try to analyze the data references in a loop contained in the SCOP. */ - -bool -scop_detection::stmt_has_simple_data_refs_p (sese_l scop, gimple *stmt) -{ - edge nest = scop.entry; - loop_p loop = loop_containing_stmt (stmt); - if (!loop_in_sese_p (loop, scop)) - loop = NULL; - - auto_vec<data_reference_p> drs; - if (! graphite_find_data_references_in_stmt (nest, loop, stmt, &drs)) - return false; - - int j; - data_reference_p dr; - FOR_EACH_VEC_ELT (drs, j, dr) - { - for (unsigned i = 0; i < DR_NUM_DIMENSIONS (dr); ++i) - if (! graphite_can_represent_scev (scop, DR_ACCESS_FN (dr, i))) - return false; - } - - return true; -} - -/* GIMPLE_ASM and GIMPLE_CALL may embed arbitrary side effects. - Calls have side-effects, except those to const or pure - functions. */ - -static bool -stmt_has_side_effects (gimple *stmt) -{ - if (gimple_has_volatile_ops (stmt) - || (gimple_code (stmt) == GIMPLE_CALL - && !(gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE))) - || (gimple_code (stmt) == GIMPLE_ASM)) - { - DEBUG_PRINT (dp << "[scop-detection-fail] " - << "Statement has side-effects:\n"; - print_gimple_stmt (dump_file, stmt, 0, TDF_VOPS | TDF_MEMSYMS)); - return true; - } - return false; -} - -/* Return true only when STMT is simple enough for being handled by Graphite. - This depends on SCOP, as the parameters are initialized relatively to - this basic block, the linear functions are initialized based on the outermost - loop containing STMT inside the SCOP. BB is the place where we try to - evaluate the STMT. */ - -bool -scop_detection::stmt_simple_for_scop_p (sese_l scop, gimple *stmt, - basic_block bb) const -{ - gcc_assert (scop); - - if (is_gimple_debug (stmt)) - return true; - - if (stmt_has_side_effects (stmt)) - return false; - - if (!stmt_has_simple_data_refs_p (scop, stmt)) - { - DEBUG_PRINT (dp << "[scop-detection-fail] " - << "Graphite cannot handle data-refs in stmt:\n"; - print_gimple_stmt (dump_file, stmt, 0, TDF_VOPS|TDF_MEMSYMS);); - return false; - } - - switch (gimple_code (stmt)) - { - case GIMPLE_LABEL: - return true; - - case GIMPLE_COND: - { - /* We can handle all binary comparisons. Inequalities are - also supported as they can be represented with union of - polyhedra. */ - enum tree_code code = gimple_cond_code (stmt); - if (!(code == LT_EXPR - || code == GT_EXPR - || code == LE_EXPR - || code == GE_EXPR - || code == EQ_EXPR - || code == NE_EXPR)) - { - DEBUG_PRINT (dp << "[scop-detection-fail] " - << "Graphite cannot handle cond stmt:\n"; - print_gimple_stmt (dump_file, stmt, 0, - TDF_VOPS | TDF_MEMSYMS)); - return false; - } - - loop_p loop = bb->loop_father; - for (unsigned i = 0; i < 2; ++i) - { - tree op = gimple_op (stmt, i); - if (!graphite_can_represent_expr (scop, loop, op) - /* We can only constrain on integer type. */ - || ! INTEGRAL_TYPE_P (TREE_TYPE (op))) - { - DEBUG_PRINT (dp << "[scop-detection-fail] " - << "Graphite cannot represent stmt:\n"; - print_gimple_stmt (dump_file, stmt, 0, - TDF_VOPS | TDF_MEMSYMS)); - return false; - } - } - - return true; - } - - case GIMPLE_ASSIGN: - case GIMPLE_CALL: - { - tree op, lhs = gimple_get_lhs (stmt); - ssa_op_iter i; - /* If we are not going to instantiate the stmt do not require - its operands to be instantiatable at this point. */ - if (lhs - && TREE_CODE (lhs) == SSA_NAME - && scev_analyzable_p (lhs, scop)) - return true; - /* Verify that if we can analyze operands at their def site we - also can represent them when analyzed at their uses. */ - FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_USE) - if (scev_analyzable_p (op, scop) - && chrec_contains_undetermined - (cached_scalar_evolution_in_region (scop, - bb->loop_father, op))) - { - DEBUG_PRINT (dp << "[scop-detection-fail] " - << "Graphite cannot code-gen stmt:\n"; - print_gimple_stmt (dump_file, stmt, 0, - TDF_VOPS | TDF_MEMSYMS)); - return false; - } - return true; - } - - default: - /* These nodes cut a new scope. */ - DEBUG_PRINT ( - dp << "[scop-detection-fail] " - << "Gimple stmt not handled in Graphite:\n"; - print_gimple_stmt (dump_file, stmt, 0, TDF_VOPS | TDF_MEMSYMS)); - return false; - } -} - -/* Returns the number of pbbs that are in loops contained in SCOP. */ - -int -scop_detection::nb_pbbs_in_loops (scop_p scop) -{ - int i; - poly_bb_p pbb; - int res = 0; - - FOR_EACH_VEC_ELT (scop->pbbs, i, pbb) - if (loop_in_sese_p (gbb_loop (PBB_BLACK_BOX (pbb)), scop->scop_info->region)) - res++; - - return res; -} - -/* Assigns the parameter NAME an index in REGION. */ - -static void -assign_parameter_index_in_region (tree name, sese_info_p region) -{ - gcc_assert (TREE_CODE (name) == SSA_NAME - && ! defined_in_sese_p (name, region->region)); - int i; - tree p; - FOR_EACH_VEC_ELT (region->params, i, p) - if (p == name) - return; - - region->params.safe_push (name); -} - -/* In the context of sese S, scan the expression E and translate it to - a linear expression C. When parsing a symbolic multiplication, K - represents the constant multiplier of an expression containing - parameters. */ - -static void -scan_tree_for_params (sese_info_p s, tree e) -{ - if (e == chrec_dont_know) - return; - - switch (TREE_CODE (e)) - { - case POLYNOMIAL_CHREC: - scan_tree_for_params (s, CHREC_LEFT (e)); - break; - - case MULT_EXPR: - if (chrec_contains_symbols (TREE_OPERAND (e, 0))) - scan_tree_for_params (s, TREE_OPERAND (e, 0)); - else - scan_tree_for_params (s, TREE_OPERAND (e, 1)); - break; - - case PLUS_EXPR: - case POINTER_PLUS_EXPR: - case MINUS_EXPR: - scan_tree_for_params (s, TREE_OPERAND (e, 0)); - scan_tree_for_params (s, TREE_OPERAND (e, 1)); - break; - - case NEGATE_EXPR: - case BIT_NOT_EXPR: - CASE_CONVERT: - case NON_LVALUE_EXPR: - scan_tree_for_params (s, TREE_OPERAND (e, 0)); - break; - - case SSA_NAME: - assign_parameter_index_in_region (e, s); - break; - - case INTEGER_CST: - case ADDR_EXPR: - case REAL_CST: - case COMPLEX_CST: - case VECTOR_CST: - break; - - default: - gcc_unreachable (); - break; - } -} - -/* Find parameters with respect to REGION in BB. We are looking in memory - access functions, conditions and loop bounds. */ - -static void -find_params_in_bb (sese_info_p region, gimple_poly_bb_p gbb) -{ - /* Find parameters in the access functions of data references. */ - int i; - data_reference_p dr; - FOR_EACH_VEC_ELT (GBB_DATA_REFS (gbb), i, dr) - for (unsigned j = 0; j < DR_NUM_DIMENSIONS (dr); j++) - scan_tree_for_params (region, DR_ACCESS_FN (dr, j)); - - /* Find parameters in conditional statements. */ - gimple *stmt; - FOR_EACH_VEC_ELT (GBB_CONDITIONS (gbb), i, stmt) - { - loop_p loop = gimple_bb (stmt)->loop_father; - tree lhs = cached_scalar_evolution_in_region (region->region, loop, - gimple_cond_lhs (stmt)); - tree rhs = cached_scalar_evolution_in_region (region->region, loop, - gimple_cond_rhs (stmt)); - gcc_assert (!chrec_contains_undetermined (lhs) - && !chrec_contains_undetermined (rhs)); - - scan_tree_for_params (region, lhs); - scan_tree_for_params (region, rhs); - } -} - -/* Record the parameters used in the SCOP BBs. A variable is a parameter - in a scop if it does not vary during the execution of that scop. */ - -static void -find_scop_parameters (scop_p scop) -{ - unsigned i; - sese_info_p region = scop->scop_info; - - /* Parameters used in loop bounds are processed during gather_bbs. */ - - /* Find the parameters used in data accesses. */ - poly_bb_p pbb; - FOR_EACH_VEC_ELT (scop->pbbs, i, pbb) - find_params_in_bb (region, PBB_BLACK_BOX (pbb)); - - int nbp = sese_nb_params (region); - scop_set_nb_params (scop, nbp); -} - -static void -add_write (vec<tree> *writes, tree def) -{ - writes->safe_push (def); - DEBUG_PRINT (dp << "Adding scalar write: "; - print_generic_expr (dump_file, def); - dp << "\nFrom stmt: "; - print_gimple_stmt (dump_file, - SSA_NAME_DEF_STMT (def), 0)); -} - -static void -add_read (vec<scalar_use> *reads, tree use, gimple *use_stmt) -{ - DEBUG_PRINT (dp << "Adding scalar read: "; - print_generic_expr (dump_file, use); - dp << "\nFrom stmt: "; - print_gimple_stmt (dump_file, use_stmt, 0)); - reads->safe_push (std::make_pair (use_stmt, use)); -} - - -/* Record DEF if it is used in other bbs different than DEF_BB in the SCOP. */ - -static void -build_cross_bb_scalars_def (scop_p scop, tree def, basic_block def_bb, - vec<tree> *writes) -{ - if (!is_gimple_reg (def)) - return; - - bool scev_analyzable = scev_analyzable_p (def, scop->scop_info->region); - - gimple *use_stmt; - imm_use_iterator imm_iter; - FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, def) - /* Do not gather scalar variables that can be analyzed by SCEV as they can - be generated out of the induction variables. */ - if ((! scev_analyzable - /* But gather SESE liveouts as we otherwise fail to rewrite their - exit PHIs. */ - || ! bb_in_sese_p (gimple_bb (use_stmt), scop->scop_info->region)) - && (def_bb != gimple_bb (use_stmt) && !is_gimple_debug (use_stmt))) - { - add_write (writes, def); - break; - } -} - -/* Record USE if it is defined in other bbs different than USE_STMT - in the SCOP. */ - -static void -build_cross_bb_scalars_use (scop_p scop, tree use, gimple *use_stmt, - vec<scalar_use> *reads) -{ - if (!is_gimple_reg (use)) - return; - - /* Do not gather scalar variables that can be analyzed by SCEV as they can be - generated out of the induction variables. */ - if (scev_analyzable_p (use, scop->scop_info->region)) - return; - - gimple *def_stmt = SSA_NAME_DEF_STMT (use); - if (gimple_bb (def_stmt) != gimple_bb (use_stmt)) - add_read (reads, use, use_stmt); -} - -/* Generates a polyhedral black box only if the bb contains interesting - information. */ - -static gimple_poly_bb_p -try_generate_gimple_bb (scop_p scop, basic_block bb) -{ - vec<data_reference_p> drs = vNULL; - vec<tree> writes = vNULL; - vec<scalar_use> reads = vNULL; - - sese_l region = scop->scop_info->region; - edge nest = region.entry; - loop_p loop = bb->loop_father; - if (!loop_in_sese_p (loop, region)) - loop = NULL; - - for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); - gsi_next (&gsi)) - { - gimple *stmt = gsi_stmt (gsi); - if (is_gimple_debug (stmt)) - continue; - - graphite_find_data_references_in_stmt (nest, loop, stmt, &drs); - - tree def = gimple_get_lhs (stmt); - if (def) - build_cross_bb_scalars_def (scop, def, gimple_bb (stmt), &writes); - - ssa_op_iter iter; - tree use; - FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE) - build_cross_bb_scalars_use (scop, use, stmt, &reads); - } - - /* Handle defs and uses in PHIs. Those need special treatment given - that we have to present ISL with sth that looks like we've rewritten - the IL out-of-SSA. */ - for (gphi_iterator psi = gsi_start_phis (bb); !gsi_end_p (psi); - gsi_next (&psi)) - { - gphi *phi = psi.phi (); - tree res = gimple_phi_result (phi); - if (virtual_operand_p (res) - || scev_analyzable_p (res, scop->scop_info->region)) - continue; - /* To simulate out-of-SSA the block containing the PHI node has - reads of the PHI destination. And to preserve SSA dependences - we also write to it (the out-of-SSA decl and the SSA result - are coalesced for dependence purposes which is good enough). */ - add_read (&reads, res, phi); - add_write (&writes, res); - } - basic_block bb_for_succs = bb; - if (bb_for_succs == bb_for_succs->loop_father->latch - && bb_in_sese_p (bb_for_succs, scop->scop_info->region) - && sese_trivially_empty_bb_p (bb_for_succs)) - bb_for_succs = NULL; - while (bb_for_succs) - { - basic_block latch = NULL; - edge_iterator ei; - edge e; - FOR_EACH_EDGE (e, ei, bb_for_succs->succs) - { - for (gphi_iterator psi = gsi_start_phis (e->dest); !gsi_end_p (psi); - gsi_next (&psi)) - { - gphi *phi = psi.phi (); - tree res = gimple_phi_result (phi); - if (virtual_operand_p (res)) - continue; - /* To simulate out-of-SSA the predecessor of edges into PHI nodes - has a copy from the PHI argument to the PHI destination. */ - if (! scev_analyzable_p (res, scop->scop_info->region)) - add_write (&writes, res); - tree use = PHI_ARG_DEF_FROM_EDGE (phi, e); - if (TREE_CODE (use) == SSA_NAME - && ! SSA_NAME_IS_DEFAULT_DEF (use) - && gimple_bb (SSA_NAME_DEF_STMT (use)) != bb_for_succs - && ! scev_analyzable_p (use, scop->scop_info->region)) - add_read (&reads, use, phi); - } - if (e->dest == bb_for_succs->loop_father->latch - && bb_in_sese_p (e->dest, scop->scop_info->region) - && sese_trivially_empty_bb_p (e->dest)) - latch = e->dest; - } - /* Handle empty latch block PHIs here, otherwise we confuse ISL - with extra conditional code where it then peels off the last - iteration just because of that. It would be simplest if we - just didn't force simple latches (thus remove the forwarder). */ - bb_for_succs = latch; - } - - /* For the region exit block add reads for all live-out vars. */ - if (bb == scop->scop_info->region.exit->src) - { - sese_build_liveouts (scop->scop_info); - unsigned i; - bitmap_iterator bi; - EXECUTE_IF_SET_IN_BITMAP (scop->scop_info->liveout, 0, i, bi) - { - tree use = ssa_name (i); - add_read (&reads, use, NULL); - } - } - - if (drs.is_empty () && writes.is_empty () && reads.is_empty ()) - return NULL; - - return new_gimple_poly_bb (bb, drs, reads, writes); -} - -/* Compute alias-sets for all data references in DRS. */ - -static bool -build_alias_set (scop_p scop) -{ - int num_vertices = scop->drs.length (); - struct graph *g = new_graph (num_vertices); - dr_info *dr1, *dr2; - int i, j; - int *all_vertices; - - struct loop *nest - = find_common_loop (scop->scop_info->region.entry->dest->loop_father, - scop->scop_info->region.exit->src->loop_father); - - FOR_EACH_VEC_ELT (scop->drs, i, dr1) - for (j = i+1; scop->drs.iterate (j, &dr2); j++) - if (dr_may_alias_p (dr1->dr, dr2->dr, nest)) - { - /* Dependences in the same alias set need to be handled - by just looking at DR_ACCESS_FNs. */ - if (DR_NUM_DIMENSIONS (dr1->dr) == 0 - || DR_NUM_DIMENSIONS (dr1->dr) != DR_NUM_DIMENSIONS (dr2->dr) - || ! operand_equal_p (DR_BASE_OBJECT (dr1->dr), - DR_BASE_OBJECT (dr2->dr), - OEP_ADDRESS_OF) - || ! types_compatible_p (TREE_TYPE (DR_BASE_OBJECT (dr1->dr)), - TREE_TYPE (DR_BASE_OBJECT (dr2->dr)))) - { - free_graph (g); - return false; - } - add_edge (g, i, j); - add_edge (g, j, i); - } - - all_vertices = XNEWVEC (int, num_vertices); - for (i = 0; i < num_vertices; i++) - all_vertices[i] = i; - - scop->max_alias_set - = graphds_dfs (g, all_vertices, num_vertices, NULL, true, NULL) + 1; - free (all_vertices); - - for (i = 0; i < g->n_vertices; i++) - scop->drs[i].alias_set = g->vertices[i].component + 1; - - free_graph (g); - return true; -} - -/* Gather BBs and conditions for a SCOP. */ -class gather_bbs : public dom_walker -{ -public: - gather_bbs (cdi_direction, scop_p, int *); - - virtual edge before_dom_children (basic_block); - virtual void after_dom_children (basic_block); - -private: - auto_vec<gimple *, 3> conditions, cases; - scop_p scop; -}; -} -gather_bbs::gather_bbs (cdi_direction direction, scop_p scop, int *bb_to_rpo) - : dom_walker (direction, ALL_BLOCKS, bb_to_rpo), scop (scop) -{ -} - -/* Call-back for dom_walk executed before visiting the dominated - blocks. */ - -edge -gather_bbs::before_dom_children (basic_block bb) -{ - sese_info_p region = scop->scop_info; - if (!bb_in_sese_p (bb, region->region)) - return dom_walker::STOP; - - /* For loops fully contained in the region record parameters in the - loop bounds. */ - loop_p loop = bb->loop_father; - if (loop->header == bb - && loop_in_sese_p (loop, region->region)) - { - tree nb_iters = number_of_latch_executions (loop); - if (chrec_contains_symbols (nb_iters)) - { - nb_iters = cached_scalar_evolution_in_region (region->region, - loop, nb_iters); - scan_tree_for_params (region, nb_iters); - } - } - - if (gcond *stmt = single_pred_cond_non_loop_exit (bb)) - { - edge e = single_pred_edge (bb); - /* Make sure the condition is in the region and thus was verified - to be handled. */ - if (e != region->region.entry) - { - conditions.safe_push (stmt); - if (e->flags & EDGE_TRUE_VALUE) - cases.safe_push (stmt); - else - cases.safe_push (NULL); - } - } - - scop->scop_info->bbs.safe_push (bb); - - gimple_poly_bb_p gbb = try_generate_gimple_bb (scop, bb); - if (!gbb) - return NULL; - - GBB_CONDITIONS (gbb) = conditions.copy (); - GBB_CONDITION_CASES (gbb) = cases.copy (); - - poly_bb_p pbb = new_poly_bb (scop, gbb); - scop->pbbs.safe_push (pbb); - - int i; - data_reference_p dr; - FOR_EACH_VEC_ELT (gbb->data_refs, i, dr) - { - DEBUG_PRINT (dp << "Adding memory "; - if (dr->is_read) - dp << "read: "; - else - dp << "write: "; - print_generic_expr (dump_file, dr->ref); - dp << "\nFrom stmt: "; - print_gimple_stmt (dump_file, dr->stmt, 0)); - - scop->drs.safe_push (dr_info (dr, pbb)); - } - - return NULL; -} - -/* Call-back for dom_walk executed after visiting the dominated - blocks. */ - -void -gather_bbs::after_dom_children (basic_block bb) -{ - if (!bb_in_sese_p (bb, scop->scop_info->region)) - return; - - if (single_pred_cond_non_loop_exit (bb)) - { - edge e = single_pred_edge (bb); - if (e != scop->scop_info->region.entry) - { - conditions.pop (); - cases.pop (); - } - } -} - - -/* Compute sth like an execution order, dominator order with first executing - edges that stay inside the current loop, delaying processing exit edges. */ - -static int *bb_to_rpo; - -/* Helper for qsort, sorting after order above. */ - -static int -cmp_pbbs (const void *pa, const void *pb) -{ - poly_bb_p bb1 = *((const poly_bb_p *)pa); - poly_bb_p bb2 = *((const poly_bb_p *)pb); - if (bb_to_rpo[bb1->black_box->bb->index] - < bb_to_rpo[bb2->black_box->bb->index]) - return -1; - else if (bb_to_rpo[bb1->black_box->bb->index] - > bb_to_rpo[bb2->black_box->bb->index]) - return 1; - else - return 0; -} - -/* Find Static Control Parts (SCoP) in the current function and pushes - them to SCOPS. */ - -void -build_scops (vec<scop_p> *scops) -{ - if (dump_file) - dp.set_dump_file (dump_file); - - scop_detection sb; - sb.build_scop_depth (current_loops->tree_root); - - /* Now create scops from the lightweight SESEs. */ - vec<sese_l> scops_l = sb.get_scops (); - - /* Domwalk needs a bb to RPO mapping. Compute it once here. */ - int *postorder = XNEWVEC (int, n_basic_blocks_for_fn (cfun)); - int postorder_num = pre_and_rev_post_order_compute (NULL, postorder, true); - bb_to_rpo = XNEWVEC (int, last_basic_block_for_fn (cfun)); - for (int i = 0; i < postorder_num; ++i) - bb_to_rpo[postorder[i]] = i; - free (postorder); - - int i; - sese_l *s; - FOR_EACH_VEC_ELT (scops_l, i, s) - { - scop_p scop = new_scop (s->entry, s->exit); - - /* Record all basic blocks and their conditions in REGION. */ - gather_bbs (CDI_DOMINATORS, scop, bb_to_rpo).walk (s->entry->dest); - - /* Sort pbbs after execution order for initial schedule generation. */ - scop->pbbs.qsort (cmp_pbbs); - - if (! build_alias_set (scop)) - { - DEBUG_PRINT (dp << "[scop-detection-fail] cannot handle dependences\n"); - free_scop (scop); - continue; - } - - /* Do not optimize a scop containing only PBBs that do not belong - to any loops. */ - if (sb.nb_pbbs_in_loops (scop) == 0) - { - DEBUG_PRINT (dp << "[scop-detection-fail] no data references.\n"); - free_scop (scop); - continue; - } - - unsigned max_arrays = param_graphite_max_arrays_per_scop; - if (max_arrays > 0 - && scop->drs.length () >= max_arrays) - { - DEBUG_PRINT (dp << "[scop-detection-fail] too many data references: " - << scop->drs.length () - << " is larger than --param graphite-max-arrays-per-scop=" - << max_arrays << ".\n"); - free_scop (scop); - continue; - } - - find_scop_parameters (scop); - graphite_dim_t max_dim = param_graphite_max_nb_scop_params; - if (max_dim > 0 - && scop_nb_params (scop) > max_dim) - { - DEBUG_PRINT (dp << "[scop-detection-fail] too many parameters: " - << scop_nb_params (scop) - << " larger than --param graphite-max-nb-scop-params=" - << max_dim << ".\n"); - free_scop (scop); - continue; - } - - scops->safe_push (scop); - } - - free (bb_to_rpo); - bb_to_rpo = NULL; - DEBUG_PRINT (dp << "number of SCoPs: " << (scops ? scops->length () : 0);); -} - -#endif /* HAVE_isl */ |