2016-01-15 Vladimir Makarov <vmakarov@redhat.com>
[official-gcc.git] / gcc / graphite-optimize-isl.c
blob1e1d02047ecfa9fcf942160b91830885e52fe6ef
1 /* A scheduling optimizer for Graphite
2 Copyright (C) 2012-2016 Free Software Foundation, Inc.
3 Contributed by Tobias Grosser <tobias@grosser.es>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #define USES_ISL
23 #include "config.h"
25 #ifdef HAVE_isl
27 #include "system.h"
28 #include "coretypes.h"
29 #include "backend.h"
30 #include "cfghooks.h"
31 #include "tree.h"
32 #include "gimple.h"
33 #include "fold-const.h"
34 #include "gimple-iterator.h"
35 #include "tree-ssa-loop.h"
36 #include "cfgloop.h"
37 #include "tree-data-ref.h"
38 #include "params.h"
39 #include "dumpfile.h"
40 #include "graphite.h"
42 #ifdef HAVE_ISL_OPTIONS_SET_SCHEDULE_SERIALIZE_SCCS
43 /* isl 0.15 or later. */
45 /* get_schedule_for_node_st - Improve schedule for the schedule node.
46 Only Simple loop tiling is considered. */
48 static __isl_give isl_schedule_node *
49 get_schedule_for_node_st (__isl_take isl_schedule_node *node, void *user)
51 if (user)
52 return node;
54 if (isl_schedule_node_get_type (node) != isl_schedule_node_band
55 || isl_schedule_node_n_children (node) != 1)
56 return node;
58 isl_space *space = isl_schedule_node_band_get_space (node);
59 unsigned dims = isl_space_dim (space, isl_dim_set);
60 isl_schedule_node *child = isl_schedule_node_get_child (node, 0);
61 isl_schedule_node_type type = isl_schedule_node_get_type (child);
62 isl_space_free (space);
63 isl_schedule_node_free (child);
65 if (type != isl_schedule_node_leaf)
66 return node;
68 if (dims <= 1 || !isl_schedule_node_band_get_permutable (node))
70 if (dump_file && dump_flags)
71 fprintf (dump_file, "not tiled\n");
72 return node;
75 /* Tile loops. */
76 space = isl_schedule_node_band_get_space (node);
77 isl_multi_val *sizes = isl_multi_val_zero (space);
78 long tile_size = PARAM_VALUE (PARAM_LOOP_BLOCK_TILE_SIZE);
79 isl_ctx *ctx = isl_schedule_node_get_ctx (node);
81 for (unsigned i = 0; i < dims; i++)
83 sizes = isl_multi_val_set_val (sizes, i,
84 isl_val_int_from_si (ctx, tile_size));
85 if (dump_file && dump_flags)
86 fprintf (dump_file, "tiled by %ld\n", tile_size);
89 node = isl_schedule_node_band_tile (node, sizes);
90 node = isl_schedule_node_child (node, 0);
92 return node;
95 /* get_schedule_map_st - Improve the schedule by performing other loop
96 optimizations. _st ending is for schedule tree version of this
97 function (see get_schedule_map below for the band forest version).
99 Do a depth-first post-order traversal of the nodes in a schedule
100 tree and apply get_schedule_for_node_st on them to improve the schedule.
103 static __isl_give isl_union_map *
104 get_schedule_map_st (__isl_keep isl_schedule *schedule)
107 schedule = isl_schedule_map_schedule_node_bottom_up (schedule,
108 get_schedule_for_node_st,
109 NULL);
110 isl_union_map *schedule_map = isl_schedule_get_map (schedule);
111 return schedule_map;
113 #else
115 /* get_tile_map - Create a map that describes a n-dimensonal tiling.
117 get_tile_map creates a map from a n-dimensional scattering space into an
118 2*n-dimensional scattering space. The map describes a rectangular tiling.
120 Example:
121 SCHEDULE_DIMENSIONS = 2, PARAMETER_DIMENSIONS = 1, TILE_SIZE = 32
123 tile_map := [p0] -> {[s0, s1] -> [t0, t1, s0, s1]:
124 t0 % 32 = 0 and t0 <= s0 < t0 + 32 and
125 t1 % 32 = 0 and t1 <= s1 < t1 + 32}
127 Before tiling:
129 for (i = 0; i < N; i++)
130 for (j = 0; j < M; j++)
131 S(i,j)
133 After tiling:
135 for (t_i = 0; t_i < N; i+=32)
136 for (t_j = 0; t_j < M; j+=32)
137 for (i = t_i; i < min(t_i + 32, N); i++) | Unknown that N % 32 = 0
138 for (j = t_j; j < t_j + 32; j++) | Known that M % 32 = 0
139 S(i,j)
142 static isl_basic_map *
143 get_tile_map (isl_ctx *ctx, int schedule_dimensions, int tile_size)
145 /* We construct
147 tile_map := [p0] -> {[s0, s1] -> [t0, t1, p0, p1, a0, a1]:
148 s0 = a0 * 32 and s0 = p0 and t0 <= p0 < t0 + 32 and
149 s1 = a1 * 32 and s1 = p1 and t1 <= p1 < t1 + 32}
151 and project out the auxilary dimensions a0 and a1. */
152 isl_space *space
153 = isl_space_alloc (ctx, 0, schedule_dimensions, schedule_dimensions * 3);
154 isl_basic_map *tile_map = isl_basic_map_universe (isl_space_copy (space));
156 isl_local_space *local_space = isl_local_space_from_space (space);
158 for (int x = 0; x < schedule_dimensions; x++)
160 int sX = x;
161 int tX = x;
162 int pX = schedule_dimensions + x;
163 int aX = 2 * schedule_dimensions + x;
165 isl_constraint *c;
167 /* sX = aX * tile_size; */
168 c = isl_equality_alloc (isl_local_space_copy (local_space));
169 isl_constraint_set_coefficient_si (c, isl_dim_out, sX, 1);
170 isl_constraint_set_coefficient_si (c, isl_dim_out, aX, -tile_size);
171 tile_map = isl_basic_map_add_constraint (tile_map, c);
173 /* pX = sX; */
174 c = isl_equality_alloc (isl_local_space_copy (local_space));
175 isl_constraint_set_coefficient_si (c, isl_dim_out, pX, 1);
176 isl_constraint_set_coefficient_si (c, isl_dim_in, sX, -1);
177 tile_map = isl_basic_map_add_constraint (tile_map, c);
179 /* tX <= pX */
180 c = isl_inequality_alloc (isl_local_space_copy (local_space));
181 isl_constraint_set_coefficient_si (c, isl_dim_out, pX, 1);
182 isl_constraint_set_coefficient_si (c, isl_dim_out, tX, -1);
183 tile_map = isl_basic_map_add_constraint (tile_map, c);
185 /* pX <= tX + (tile_size - 1) */
186 c = isl_inequality_alloc (isl_local_space_copy (local_space));
187 isl_constraint_set_coefficient_si (c, isl_dim_out, tX, 1);
188 isl_constraint_set_coefficient_si (c, isl_dim_out, pX, -1);
189 isl_constraint_set_constant_si (c, tile_size - 1);
190 tile_map = isl_basic_map_add_constraint (tile_map, c);
193 /* Project out auxiliary dimensions.
195 The auxiliary dimensions are transformed into existentially quantified
196 ones.
197 This reduces the number of visible scattering dimensions and allows isl
198 to produces better code. */
199 tile_map =
200 isl_basic_map_project_out (tile_map, isl_dim_out,
201 2 * schedule_dimensions, schedule_dimensions);
202 isl_local_space_free (local_space);
203 return tile_map;
206 /* get_schedule_for_band - Get the schedule for this BAND.
208 Polly applies transformations like tiling on top of the isl calculated
209 value.
210 This can influence the number of scheduling dimension. The number of
211 schedule dimensions is returned in DIMENSIONS. */
213 static isl_union_map *
214 get_schedule_for_band (isl_band *band, int *dimensions)
216 isl_union_map *partial_schedule;
217 isl_ctx *ctx;
218 isl_space *space;
219 isl_basic_map *tile_map;
220 isl_union_map *tile_umap;
222 partial_schedule = isl_band_get_partial_schedule (band);
223 *dimensions = isl_band_n_member (band);
225 /* It does not make any sense to tile a band with just one dimension. */
226 if (*dimensions == 1)
228 if (dump_file && dump_flags)
229 fprintf (dump_file, "not tiled\n");
230 return partial_schedule;
233 if (dump_file && dump_flags)
234 fprintf (dump_file, "tiled by %d\n",
235 PARAM_VALUE (PARAM_LOOP_BLOCK_TILE_SIZE));
237 ctx = isl_union_map_get_ctx (partial_schedule);
238 space = isl_union_map_get_space (partial_schedule);
240 tile_map = get_tile_map (ctx, *dimensions,
241 PARAM_VALUE (PARAM_LOOP_BLOCK_TILE_SIZE));
242 tile_umap = isl_union_map_from_map (isl_map_from_basic_map (tile_map));
243 tile_umap = isl_union_map_align_params (tile_umap, space);
244 *dimensions = 2 * *dimensions;
246 return isl_union_map_apply_range (partial_schedule, tile_umap);
250 /* get_schedule_for_band_list - Get the scheduling map for a list of bands.
252 We walk recursively the forest of bands to combine the schedules of the
253 individual bands to the overall schedule. In case tiling is requested,
254 the individual bands are tiled. */
256 static isl_union_map *
257 get_schedule_for_band_list (isl_band_list *band_list)
259 int num_bands, i;
260 isl_union_map *schedule;
261 isl_ctx *ctx;
263 ctx = isl_band_list_get_ctx (band_list);
264 num_bands = isl_band_list_n_band (band_list);
265 schedule = isl_union_map_empty (isl_space_params_alloc (ctx, 0));
267 for (i = 0; i < num_bands; i++)
269 isl_band *band;
270 isl_union_map *partial_schedule;
271 int schedule_dimensions;
272 isl_space *space;
274 band = isl_band_list_get_band (band_list, i);
275 partial_schedule = get_schedule_for_band (band, &schedule_dimensions);
276 space = isl_union_map_get_space (partial_schedule);
278 if (isl_band_has_children (band))
280 isl_band_list *children = isl_band_get_children (band);
281 isl_union_map *suffixSchedule
282 = get_schedule_for_band_list (children);
283 partial_schedule
284 = isl_union_map_flat_range_product (partial_schedule,
285 suffixSchedule);
286 isl_band_list_free (children);
289 schedule = isl_union_map_union (schedule, partial_schedule);
291 isl_band_free (band);
292 isl_space_free (space);
295 return schedule;
298 static isl_union_map *
299 get_schedule_map (isl_schedule *schedule)
301 isl_band_list *bandList = isl_schedule_get_band_forest (schedule);
302 isl_union_map *schedule_map = get_schedule_for_band_list (bandList);
303 isl_band_list_free (bandList);
304 return schedule_map;
306 #endif
308 static isl_stat
309 get_single_map (__isl_take isl_map *map, void *user)
311 isl_map **single_map = (isl_map **)user;
312 *single_map = map;
313 return isl_stat_ok;
316 static void
317 apply_schedule_map_to_scop (scop_p scop, isl_union_map *schedule_map)
319 int i;
320 poly_bb_p pbb;
322 FOR_EACH_VEC_ELT (scop->pbbs, i, pbb)
324 isl_set *domain = isl_set_copy (pbb->domain);
325 isl_map *stmt_schedule;
327 isl_union_map *stmt_band
328 = isl_union_map_intersect_domain (isl_union_map_copy (schedule_map),
329 isl_union_set_from_set (domain));
330 isl_union_map_foreach_map (stmt_band, get_single_map, &stmt_schedule);
331 isl_map_free (pbb->transformed);
332 pbb->transformed = stmt_schedule;
333 isl_union_map_free (stmt_band);
337 static isl_union_set *
338 scop_get_domains (scop_p scop ATTRIBUTE_UNUSED)
340 int i;
341 poly_bb_p pbb;
342 isl_space *space = isl_set_get_space (scop->param_context);
343 isl_union_set *res = isl_union_set_empty (space);
345 FOR_EACH_VEC_ELT (scop->pbbs, i, pbb)
346 res = isl_union_set_add_set (res, isl_set_copy (pbb->domain));
348 return res;
351 static const int CONSTANT_BOUND = 20;
353 /* Compute the schedule for SCOP based on its parameters, domain and set of
354 constraints. Then apply the schedule to SCOP. */
356 bool
357 optimize_isl (scop_p scop)
359 int old_max_operations = isl_ctx_get_max_operations (scop->isl_context);
360 int max_operations = PARAM_VALUE (PARAM_MAX_ISL_OPERATIONS);
361 if (max_operations)
362 isl_ctx_set_max_operations (scop->isl_context, max_operations);
363 isl_options_set_on_error (scop->isl_context, ISL_ON_ERROR_CONTINUE);
365 isl_union_set *domain = scop_get_domains (scop);
366 scop_get_dependences (scop);
367 scop->dependence
368 = isl_union_map_gist_domain (scop->dependence, isl_union_set_copy (domain));
369 scop->dependence
370 = isl_union_map_gist_range (scop->dependence, isl_union_set_copy (domain));
371 isl_union_map *validity = isl_union_map_copy (scop->dependence);
372 isl_union_map *proximity = isl_union_map_copy (validity);
374 isl_options_set_schedule_max_constant_term (scop->isl_context, CONSTANT_BOUND);
375 isl_options_set_schedule_maximize_band_depth (scop->isl_context, 1);
376 #ifdef HAVE_ISL_OPTIONS_SET_SCHEDULE_SERIALIZE_SCCS
377 /* isl 0.15 or later. */
378 isl_options_set_schedule_serialize_sccs (scop->isl_context, 0);
379 isl_options_set_schedule_maximize_band_depth (scop->isl_context, 1);
380 isl_options_set_schedule_max_constant_term (scop->isl_context, 20);
381 isl_options_set_schedule_max_coefficient (scop->isl_context, 20);
382 isl_options_set_tile_scale_tile_loops (scop->isl_context, 0);
383 isl_options_set_coalesce_bounded_wrapping (scop->isl_context, 1);
384 isl_options_set_ast_build_exploit_nested_bounds (scop->isl_context, 1);
385 isl_options_set_ast_build_atomic_upper_bound (scop->isl_context, 1);
386 #else
387 isl_options_set_schedule_fuse (scop->isl_context, ISL_SCHEDULE_FUSE_MIN);
388 #endif
390 isl_schedule *schedule
391 = isl_union_set_compute_schedule (domain, validity, proximity);
392 isl_options_set_on_error (scop->isl_context, ISL_ON_ERROR_ABORT);
394 isl_ctx_reset_operations (scop->isl_context);
395 isl_ctx_set_max_operations (scop->isl_context, old_max_operations);
396 if (!schedule || isl_ctx_last_error (scop->isl_context) == isl_error_quota)
398 if (dump_file && dump_flags)
399 fprintf (dump_file, "isl timed out --param max-isl-operations=%d\n",
400 max_operations);
401 if (schedule)
402 isl_schedule_free (schedule);
403 return false;
406 /* Attach the schedule to scop so that it can be used in code generation.
407 schedule freeing will occur in code generation. */
408 scop->schedule = schedule;
410 #ifdef HAVE_ISL_OPTIONS_SET_SCHEDULE_SERIALIZE_SCCS
411 /* isl 0.15 or later. */
412 isl_union_map *schedule_map = get_schedule_map_st (schedule);
413 #else
414 isl_union_map *schedule_map = get_schedule_map (schedule);
415 #endif
416 apply_schedule_map_to_scop (scop, schedule_map);
418 isl_union_map_free (schedule_map);
419 return true;
422 #endif /* HAVE_isl */