11debfc3dSmrg /* A scheduling optimizer for Graphite
2*8feb0f0bSmrg Copyright (C) 2012-2020 Free Software Foundation, Inc.
31debfc3dSmrg Contributed by Tobias Grosser <tobias@grosser.es>.
41debfc3dSmrg
51debfc3dSmrg This file is part of GCC.
61debfc3dSmrg
71debfc3dSmrg GCC is free software; you can redistribute it and/or modify
81debfc3dSmrg it under the terms of the GNU General Public License as published by
91debfc3dSmrg the Free Software Foundation; either version 3, or (at your option)
101debfc3dSmrg any later version.
111debfc3dSmrg
121debfc3dSmrg GCC is distributed in the hope that it will be useful,
131debfc3dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
141debfc3dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
151debfc3dSmrg GNU General Public License for more details.
161debfc3dSmrg
171debfc3dSmrg You should have received a copy of the GNU General Public License
181debfc3dSmrg along with GCC; see the file COPYING3. If not see
191debfc3dSmrg <http://www.gnu.org/licenses/>. */
201debfc3dSmrg
211debfc3dSmrg #define USES_ISL
221debfc3dSmrg
231debfc3dSmrg #include "config.h"
241debfc3dSmrg
251debfc3dSmrg #ifdef HAVE_isl
261debfc3dSmrg
271debfc3dSmrg #include "system.h"
281debfc3dSmrg #include "coretypes.h"
291debfc3dSmrg #include "backend.h"
301debfc3dSmrg #include "cfghooks.h"
311debfc3dSmrg #include "tree.h"
321debfc3dSmrg #include "gimple.h"
331debfc3dSmrg #include "fold-const.h"
341debfc3dSmrg #include "gimple-iterator.h"
351debfc3dSmrg #include "tree-ssa-loop.h"
361debfc3dSmrg #include "cfgloop.h"
371debfc3dSmrg #include "tree-data-ref.h"
381debfc3dSmrg #include "dumpfile.h"
39a2dc1f3fSmrg #include "tree-vectorizer.h"
401debfc3dSmrg #include "graphite.h"
411debfc3dSmrg
421debfc3dSmrg
431debfc3dSmrg /* get_schedule_for_node_st - Improve schedule for the schedule node.
441debfc3dSmrg Only Simple loop tiling is considered. */
451debfc3dSmrg
461debfc3dSmrg static __isl_give isl_schedule_node *
get_schedule_for_node_st(__isl_take isl_schedule_node * node,void * user)471debfc3dSmrg get_schedule_for_node_st (__isl_take isl_schedule_node *node, void *user)
481debfc3dSmrg {
491debfc3dSmrg if (user)
501debfc3dSmrg return node;
511debfc3dSmrg
521debfc3dSmrg if (isl_schedule_node_get_type (node) != isl_schedule_node_band
531debfc3dSmrg || isl_schedule_node_n_children (node) != 1)
541debfc3dSmrg return node;
551debfc3dSmrg
561debfc3dSmrg isl_space *space = isl_schedule_node_band_get_space (node);
571debfc3dSmrg unsigned dims = isl_space_dim (space, isl_dim_set);
581debfc3dSmrg isl_schedule_node *child = isl_schedule_node_get_child (node, 0);
591debfc3dSmrg isl_schedule_node_type type = isl_schedule_node_get_type (child);
601debfc3dSmrg isl_space_free (space);
611debfc3dSmrg isl_schedule_node_free (child);
621debfc3dSmrg
631debfc3dSmrg if (type != isl_schedule_node_leaf)
641debfc3dSmrg return node;
651debfc3dSmrg
66*8feb0f0bSmrg long tile_size = param_loop_block_tile_size;
67a2dc1f3fSmrg if (dims <= 1
68a2dc1f3fSmrg || tile_size == 0
69a2dc1f3fSmrg || !isl_schedule_node_band_get_permutable (node))
701debfc3dSmrg {
711debfc3dSmrg if (dump_file && dump_flags)
721debfc3dSmrg fprintf (dump_file, "not tiled\n");
731debfc3dSmrg return node;
741debfc3dSmrg }
751debfc3dSmrg
761debfc3dSmrg /* Tile loops. */
771debfc3dSmrg space = isl_schedule_node_band_get_space (node);
781debfc3dSmrg isl_multi_val *sizes = isl_multi_val_zero (space);
791debfc3dSmrg isl_ctx *ctx = isl_schedule_node_get_ctx (node);
801debfc3dSmrg
811debfc3dSmrg for (unsigned i = 0; i < dims; i++)
821debfc3dSmrg {
831debfc3dSmrg sizes = isl_multi_val_set_val (sizes, i,
841debfc3dSmrg isl_val_int_from_si (ctx, tile_size));
851debfc3dSmrg if (dump_file && dump_flags)
861debfc3dSmrg fprintf (dump_file, "tiled by %ld\n", tile_size);
871debfc3dSmrg }
881debfc3dSmrg
891debfc3dSmrg node = isl_schedule_node_band_tile (node, sizes);
901debfc3dSmrg node = isl_schedule_node_child (node, 0);
911debfc3dSmrg
921debfc3dSmrg return node;
931debfc3dSmrg }
941debfc3dSmrg
951debfc3dSmrg static isl_union_set *
scop_get_domains(scop_p scop)961debfc3dSmrg scop_get_domains (scop_p scop)
971debfc3dSmrg {
981debfc3dSmrg int i;
991debfc3dSmrg poly_bb_p pbb;
1001debfc3dSmrg isl_space *space = isl_set_get_space (scop->param_context);
1011debfc3dSmrg isl_union_set *res = isl_union_set_empty (space);
1021debfc3dSmrg
1031debfc3dSmrg FOR_EACH_VEC_ELT (scop->pbbs, i, pbb)
1041debfc3dSmrg res = isl_union_set_add_set (res, isl_set_copy (pbb->domain));
1051debfc3dSmrg
1061debfc3dSmrg return res;
1071debfc3dSmrg }
1081debfc3dSmrg
1091debfc3dSmrg /* Compute the schedule for SCOP based on its parameters, domain and set of
1101debfc3dSmrg constraints. Then apply the schedule to SCOP. */
1111debfc3dSmrg
1121debfc3dSmrg static bool
optimize_isl(scop_p scop)1131debfc3dSmrg optimize_isl (scop_p scop)
1141debfc3dSmrg {
115a2dc1f3fSmrg int old_err = isl_options_get_on_error (scop->isl_context);
1161debfc3dSmrg int old_max_operations = isl_ctx_get_max_operations (scop->isl_context);
117*8feb0f0bSmrg int max_operations = param_max_isl_operations;
1181debfc3dSmrg if (max_operations)
1191debfc3dSmrg isl_ctx_set_max_operations (scop->isl_context, max_operations);
1201debfc3dSmrg isl_options_set_on_error (scop->isl_context, ISL_ON_ERROR_CONTINUE);
1211debfc3dSmrg
1221debfc3dSmrg isl_union_set *domain = scop_get_domains (scop);
1231debfc3dSmrg
1241debfc3dSmrg /* Simplify the dependences on the domain. */
1251debfc3dSmrg scop_get_dependences (scop);
1261debfc3dSmrg isl_union_map *dependences
1271debfc3dSmrg = isl_union_map_gist_domain (isl_union_map_copy (scop->dependence),
1281debfc3dSmrg isl_union_set_copy (domain));
1291debfc3dSmrg isl_union_map *validity
1301debfc3dSmrg = isl_union_map_gist_range (dependences, isl_union_set_copy (domain));
1311debfc3dSmrg
1321debfc3dSmrg /* FIXME: proximity should not be validity. */
1331debfc3dSmrg isl_union_map *proximity = isl_union_map_copy (validity);
1341debfc3dSmrg
1351debfc3dSmrg isl_schedule_constraints *sc = isl_schedule_constraints_on_domain (domain);
1361debfc3dSmrg sc = isl_schedule_constraints_set_proximity (sc, proximity);
1371debfc3dSmrg sc = isl_schedule_constraints_set_validity (sc, isl_union_map_copy (validity));
1381debfc3dSmrg sc = isl_schedule_constraints_set_coincidence (sc, validity);
1391debfc3dSmrg
1401debfc3dSmrg isl_options_set_schedule_serialize_sccs (scop->isl_context, 0);
1411debfc3dSmrg isl_options_set_schedule_maximize_band_depth (scop->isl_context, 1);
1421debfc3dSmrg isl_options_set_schedule_max_constant_term (scop->isl_context, 20);
1431debfc3dSmrg isl_options_set_schedule_max_coefficient (scop->isl_context, 20);
1441debfc3dSmrg isl_options_set_tile_scale_tile_loops (scop->isl_context, 0);
1451debfc3dSmrg /* Generate loop upper bounds that consist of the current loop iterator, an
1461debfc3dSmrg operator (< or <=) and an expression not involving the iterator. If this
1471debfc3dSmrg option is not set, then the current loop iterator may appear several times
1481debfc3dSmrg in the upper bound. See the isl manual for more details. */
1491debfc3dSmrg isl_options_set_ast_build_atomic_upper_bound (scop->isl_context, 1);
1501debfc3dSmrg
1511debfc3dSmrg scop->transformed_schedule = isl_schedule_constraints_compute_schedule (sc);
1521debfc3dSmrg scop->transformed_schedule =
1531debfc3dSmrg isl_schedule_map_schedule_node_bottom_up (scop->transformed_schedule,
1541debfc3dSmrg get_schedule_for_node_st, NULL);
1551debfc3dSmrg
156a2dc1f3fSmrg isl_options_set_on_error (scop->isl_context, old_err);
1571debfc3dSmrg isl_ctx_reset_operations (scop->isl_context);
1581debfc3dSmrg isl_ctx_set_max_operations (scop->isl_context, old_max_operations);
1591debfc3dSmrg if (!scop->transformed_schedule
160a2dc1f3fSmrg || isl_ctx_last_error (scop->isl_context) != isl_error_none)
1611debfc3dSmrg {
162c0a68be4Smrg if (dump_enabled_p ())
163c0a68be4Smrg {
164c0a68be4Smrg dump_user_location_t loc = find_loop_location
165a2dc1f3fSmrg (scop->scop_info->region.entry->dest->loop_father);
166a2dc1f3fSmrg if (isl_ctx_last_error (scop->isl_context) == isl_error_quota)
167a2dc1f3fSmrg dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc,
168a2dc1f3fSmrg "loop nest not optimized, optimization timed out "
169a2dc1f3fSmrg "after %d operations [--param max-isl-operations]\n",
1701debfc3dSmrg max_operations);
171a2dc1f3fSmrg else
172a2dc1f3fSmrg dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc,
173a2dc1f3fSmrg "loop nest not optimized, ISL signalled an error\n");
174c0a68be4Smrg }
1751debfc3dSmrg return false;
1761debfc3dSmrg }
1771debfc3dSmrg
1781debfc3dSmrg gcc_assert (scop->original_schedule);
1791debfc3dSmrg isl_union_map *original = isl_schedule_get_map (scop->original_schedule);
1801debfc3dSmrg isl_union_map *transformed = isl_schedule_get_map (scop->transformed_schedule);
1811debfc3dSmrg bool same_schedule = isl_union_map_is_equal (original, transformed);
1821debfc3dSmrg isl_union_map_free (original);
1831debfc3dSmrg isl_union_map_free (transformed);
1841debfc3dSmrg
1851debfc3dSmrg if (same_schedule)
1861debfc3dSmrg {
187c0a68be4Smrg if (dump_enabled_p ())
188c0a68be4Smrg {
189c0a68be4Smrg dump_user_location_t loc = find_loop_location
190a2dc1f3fSmrg (scop->scop_info->region.entry->dest->loop_father);
191a2dc1f3fSmrg dump_printf_loc (MSG_NOTE, loc,
192a2dc1f3fSmrg "loop nest not optimized, optimized schedule is "
193a2dc1f3fSmrg "identical to original schedule\n");
194c0a68be4Smrg }
1951debfc3dSmrg if (dump_file)
1961debfc3dSmrg print_schedule_ast (dump_file, scop->original_schedule, scop);
1971debfc3dSmrg isl_schedule_free (scop->transformed_schedule);
1981debfc3dSmrg scop->transformed_schedule = isl_schedule_copy (scop->original_schedule);
199a2dc1f3fSmrg return flag_graphite_identity || flag_loop_parallelize_all;
2001debfc3dSmrg }
2011debfc3dSmrg
2021debfc3dSmrg return true;
2031debfc3dSmrg }
2041debfc3dSmrg
2051debfc3dSmrg /* Apply graphite transformations to all the basic blocks of SCOP. */
2061debfc3dSmrg
2071debfc3dSmrg bool
apply_poly_transforms(scop_p scop)2081debfc3dSmrg apply_poly_transforms (scop_p scop)
2091debfc3dSmrg {
2101debfc3dSmrg if (flag_loop_nest_optimize)
2111debfc3dSmrg return optimize_isl (scop);
2121debfc3dSmrg
2131debfc3dSmrg if (!flag_graphite_identity && !flag_loop_parallelize_all)
2141debfc3dSmrg return false;
2151debfc3dSmrg
2161debfc3dSmrg /* Generate code even if we did not apply any real transformation.
2171debfc3dSmrg This also allows to check the performance for the identity
2181debfc3dSmrg transformation: GIMPLE -> GRAPHITE -> GIMPLE. */
2191debfc3dSmrg gcc_assert (scop->original_schedule);
2201debfc3dSmrg scop->transformed_schedule = isl_schedule_copy (scop->original_schedule);
2211debfc3dSmrg return true;
2221debfc3dSmrg }
2231debfc3dSmrg
2241debfc3dSmrg #endif /* HAVE_isl */
225