[PR67828] don't unswitch on default defs of non-parms
[official-gcc.git] / gcc / graphite-optimize-isl.c
blob090bc01a107d070db16b0b5037dd1937460edf27
1 /* A scheduling optimizer for Graphite
2 Copyright (C) 2012-2015 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 #include "config.h"
23 #ifdef HAVE_isl
24 /* Workaround for GMP 5.1.3 bug, see PR56019. */
25 #include <stddef.h>
27 #include <isl/constraint.h>
28 #include <isl/set.h>
29 #include <isl/union_set.h>
30 #include <isl/map.h>
31 #include <isl/union_map.h>
32 #include <isl/schedule.h>
33 #include <isl/band.h>
34 #include <isl/aff.h>
35 #include <isl/options.h>
36 #include <isl/ctx.h>
38 #include "system.h"
39 #include "coretypes.h"
40 #include "backend.h"
41 #include "cfghooks.h"
42 #include "tree.h"
43 #include "gimple.h"
44 #include "fold-const.h"
45 #include "gimple-iterator.h"
46 #include "tree-ssa-loop.h"
47 #include "cfgloop.h"
48 #include "tree-data-ref.h"
49 #include "graphite-poly.h"
50 #include "params.h"
51 #include "dumpfile.h"
53 static isl_union_set *
54 scop_get_domains (scop_p scop ATTRIBUTE_UNUSED)
56 int i;
57 poly_bb_p pbb;
58 isl_space *space = isl_set_get_space (scop->param_context);
59 isl_union_set *res = isl_union_set_empty (space);
61 FOR_EACH_VEC_ELT (scop->pbbs, i, pbb)
62 res = isl_union_set_add_set (res, isl_set_copy (pbb->domain));
64 return res;
67 /* get_tile_map - Create a map that describes a n-dimensonal tiling.
69 get_tile_map creates a map from a n-dimensional scattering space into an
70 2*n-dimensional scattering space. The map describes a rectangular tiling.
72 Example:
73 SCHEDULE_DIMENSIONS = 2, PARAMETER_DIMENSIONS = 1, TILE_SIZE = 32
75 tile_map := [p0] -> {[s0, s1] -> [t0, t1, s0, s1]:
76 t0 % 32 = 0 and t0 <= s0 < t0 + 32 and
77 t1 % 32 = 0 and t1 <= s1 < t1 + 32}
79 Before tiling:
81 for (i = 0; i < N; i++)
82 for (j = 0; j < M; j++)
83 S(i,j)
85 After tiling:
87 for (t_i = 0; t_i < N; i+=32)
88 for (t_j = 0; t_j < M; j+=32)
89 for (i = t_i; i < min(t_i + 32, N); i++) | Unknown that N % 32 = 0
90 for (j = t_j; j < t_j + 32; j++) | Known that M % 32 = 0
91 S(i,j)
94 static isl_basic_map *
95 get_tile_map (isl_ctx *ctx, int schedule_dimensions, int tile_size)
97 /* We construct
99 tile_map := [p0] -> {[s0, s1] -> [t0, t1, p0, p1, a0, a1]:
100 s0 = a0 * 32 and s0 = p0 and t0 <= p0 < t0 + 32 and
101 s1 = a1 * 32 and s1 = p1 and t1 <= p1 < t1 + 32}
103 and project out the auxilary dimensions a0 and a1. */
104 isl_space *space
105 = isl_space_alloc (ctx, 0, schedule_dimensions, schedule_dimensions * 3);
106 isl_basic_map *tile_map = isl_basic_map_universe (isl_space_copy (space));
108 isl_local_space *local_space = isl_local_space_from_space (space);
110 for (int x = 0; x < schedule_dimensions; x++)
112 int sX = x;
113 int tX = x;
114 int pX = schedule_dimensions + x;
115 int aX = 2 * schedule_dimensions + x;
117 isl_constraint *c;
119 /* sX = aX * tile_size; */
120 c = isl_equality_alloc (isl_local_space_copy (local_space));
121 isl_constraint_set_coefficient_si (c, isl_dim_out, sX, 1);
122 isl_constraint_set_coefficient_si (c, isl_dim_out, aX, -tile_size);
123 tile_map = isl_basic_map_add_constraint (tile_map, c);
125 /* pX = sX; */
126 c = isl_equality_alloc (isl_local_space_copy (local_space));
127 isl_constraint_set_coefficient_si (c, isl_dim_out, pX, 1);
128 isl_constraint_set_coefficient_si (c, isl_dim_in, sX, -1);
129 tile_map = isl_basic_map_add_constraint (tile_map, c);
131 /* tX <= pX */
132 c = isl_inequality_alloc (isl_local_space_copy (local_space));
133 isl_constraint_set_coefficient_si (c, isl_dim_out, pX, 1);
134 isl_constraint_set_coefficient_si (c, isl_dim_out, tX, -1);
135 tile_map = isl_basic_map_add_constraint (tile_map, c);
137 /* pX <= tX + (tile_size - 1) */
138 c = isl_inequality_alloc (isl_local_space_copy (local_space));
139 isl_constraint_set_coefficient_si (c, isl_dim_out, tX, 1);
140 isl_constraint_set_coefficient_si (c, isl_dim_out, pX, -1);
141 isl_constraint_set_constant_si (c, tile_size - 1);
142 tile_map = isl_basic_map_add_constraint (tile_map, c);
145 /* Project out auxiliary dimensions.
147 The auxiliary dimensions are transformed into existentially quantified
148 ones.
149 This reduces the number of visible scattering dimensions and allows isl
150 to produces better code. */
151 tile_map =
152 isl_basic_map_project_out (tile_map, isl_dim_out,
153 2 * schedule_dimensions, schedule_dimensions);
154 isl_local_space_free (local_space);
155 return tile_map;
158 /* get_schedule_for_band - Get the schedule for this BAND.
160 Polly applies transformations like tiling on top of the isl calculated
161 value.
162 This can influence the number of scheduling dimension. The number of
163 schedule dimensions is returned in DIMENSIONS. */
165 static isl_union_map *
166 get_schedule_for_band (isl_band *band, int *dimensions)
168 isl_union_map *partial_schedule;
169 isl_ctx *ctx;
170 isl_space *space;
171 isl_basic_map *tile_map;
172 isl_union_map *tile_umap;
174 partial_schedule = isl_band_get_partial_schedule (band);
175 *dimensions = isl_band_n_member (band);
177 /* It does not make any sense to tile a band with just one dimension. */
178 if (*dimensions == 1)
180 if (dump_file && dump_flags)
181 fprintf (dump_file, "not tiled\n");
182 return partial_schedule;
185 if (dump_file && dump_flags)
186 fprintf (dump_file, "tiled by %d\n",
187 PARAM_VALUE (PARAM_LOOP_BLOCK_TILE_SIZE));
189 ctx = isl_union_map_get_ctx (partial_schedule);
190 space = isl_union_map_get_space (partial_schedule);
192 tile_map = get_tile_map (ctx, *dimensions,
193 PARAM_VALUE (PARAM_LOOP_BLOCK_TILE_SIZE));
194 tile_umap = isl_union_map_from_map (isl_map_from_basic_map (tile_map));
195 tile_umap = isl_union_map_align_params (tile_umap, space);
196 *dimensions = 2 * *dimensions;
198 return isl_union_map_apply_range (partial_schedule, tile_umap);
202 /* get_schedule_for_band_list - Get the scheduling map for a list of bands.
204 We walk recursively the forest of bands to combine the schedules of the
205 individual bands to the overall schedule. In case tiling is requested,
206 the individual bands are tiled. */
208 static isl_union_map *
209 get_schedule_for_band_list (isl_band_list *band_list)
211 int num_bands, i;
212 isl_union_map *schedule;
213 isl_ctx *ctx;
215 ctx = isl_band_list_get_ctx (band_list);
216 num_bands = isl_band_list_n_band (band_list);
217 schedule = isl_union_map_empty (isl_space_params_alloc (ctx, 0));
219 for (i = 0; i < num_bands; i++)
221 isl_band *band;
222 isl_union_map *partial_schedule;
223 int schedule_dimensions;
224 isl_space *space;
226 band = isl_band_list_get_band (band_list, i);
227 partial_schedule = get_schedule_for_band (band, &schedule_dimensions);
228 space = isl_union_map_get_space (partial_schedule);
230 if (isl_band_has_children (band))
232 isl_band_list *children = isl_band_get_children (band);
233 isl_union_map *suffixSchedule
234 = get_schedule_for_band_list (children);
235 partial_schedule
236 = isl_union_map_flat_range_product (partial_schedule,
237 suffixSchedule);
238 isl_band_list_free (children);
241 schedule = isl_union_map_union (schedule, partial_schedule);
243 isl_band_free (band);
244 isl_space_free (space);
247 return schedule;
250 static isl_union_map *
251 get_schedule_map (isl_schedule *schedule)
253 isl_band_list *bandList = isl_schedule_get_band_forest (schedule);
254 isl_union_map *schedule_map = get_schedule_for_band_list (bandList);
255 isl_band_list_free (bandList);
256 return schedule_map;
259 static isl_stat
260 get_single_map (__isl_take isl_map *map, void *user)
262 isl_map **single_map = (isl_map **)user;
263 *single_map = map;
264 return isl_stat_ok;
267 static void
268 apply_schedule_map_to_scop (scop_p scop, isl_union_map *schedule_map)
270 int i;
271 poly_bb_p pbb;
273 FOR_EACH_VEC_ELT (scop->pbbs, i, pbb)
275 isl_set *domain = isl_set_copy (pbb->domain);
276 isl_map *stmt_schedule;
278 isl_union_map *stmt_band
279 = isl_union_map_intersect_domain (isl_union_map_copy (schedule_map),
280 isl_union_set_from_set (domain));
281 isl_union_map_foreach_map (stmt_band, get_single_map, &stmt_schedule);
282 isl_map_free (pbb->transformed);
283 pbb->transformed = stmt_schedule;
284 isl_union_map_free (stmt_band);
288 static const int CONSTANT_BOUND = 20;
290 /* Compute the schedule for SCOP based on its parameters, domain and set of
291 constraints. Then apply the schedule to SCOP. */
293 bool
294 optimize_isl (scop_p scop)
296 #ifdef HAVE_ISL_CTX_MAX_OPERATIONS
297 int old_max_operations = isl_ctx_get_max_operations (scop->isl_context);
298 int max_operations = PARAM_VALUE (PARAM_MAX_ISL_OPERATIONS);
299 if (max_operations)
300 isl_ctx_set_max_operations (scop->isl_context, max_operations);
301 #endif
302 isl_options_set_on_error (scop->isl_context, ISL_ON_ERROR_CONTINUE);
304 isl_union_set *domain = scop_get_domains (scop);
305 isl_union_map *dependences = scop_get_dependences (scop);
306 dependences
307 = isl_union_map_gist_domain (dependences, isl_union_set_copy (domain));
308 dependences
309 = isl_union_map_gist_range (dependences, isl_union_set_copy (domain));
310 isl_union_map *validity = dependences;
311 isl_union_map *proximity = isl_union_map_copy (validity);
313 #ifdef HAVE_ISL_SCHED_CONSTRAINTS_COMPUTE_SCHEDULE
314 isl_schedule_constraints *schedule_constraints;
315 schedule_constraints = isl_schedule_constraints_on_domain (domain);
316 schedule_constraints
317 = isl_schedule_constraints_set_proximity (schedule_constraints,
318 proximity);
319 schedule_constraints
320 = isl_schedule_constraints_set_validity (schedule_constraints,
321 isl_union_map_copy (validity));
322 schedule_constraints
323 = isl_schedule_constraints_set_coincidence (schedule_constraints,
324 validity);
325 #endif
327 isl_options_set_schedule_max_constant_term (scop->isl_context, CONSTANT_BOUND);
328 isl_options_set_schedule_maximize_band_depth (scop->isl_context, 1);
329 #ifdef HAVE_ISL_OPTIONS_SET_SCHEDULE_SERIALIZE_SCCS
330 /* ISL-0.15 or later. */
331 isl_options_set_schedule_serialize_sccs (scop->isl_context, 1);
332 #else
333 isl_options_set_schedule_fuse (scop->isl_context, ISL_SCHEDULE_FUSE_MIN);
334 #endif
336 #ifdef HAVE_ISL_SCHED_CONSTRAINTS_COMPUTE_SCHEDULE
337 isl_schedule *schedule
338 = isl_schedule_constraints_compute_schedule (schedule_constraints);
339 #else
340 isl_schedule *schedule
341 = isl_union_set_compute_schedule (domain, validity, proximity);
342 #endif
344 isl_options_set_on_error (scop->isl_context, ISL_ON_ERROR_ABORT);
346 #ifdef HAVE_ISL_CTX_MAX_OPERATIONS
347 isl_ctx_reset_operations (scop->isl_context);
348 isl_ctx_set_max_operations (scop->isl_context, old_max_operations);
349 if (!schedule || isl_ctx_last_error (scop->isl_context) == isl_error_quota)
351 if (dump_file && dump_flags)
352 fprintf (dump_file, "ISL timed out at %d operations\n",
353 max_operations);
354 if (schedule)
355 isl_schedule_free (schedule);
356 return false;
358 #else
359 if (!schedule)
360 return false;
361 #endif
363 isl_union_map *schedule_map = get_schedule_map (schedule);
364 apply_schedule_map_to_scop (scop, schedule_map);
366 isl_schedule_free (schedule);
367 isl_union_map_free (schedule_map);
368 return true;
371 #endif /* HAVE_isl */