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)
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/>. */
24 /* Workaround for GMP 5.1.3 bug, see PR56019. */
27 #include <isl/constraint.h>
29 #include <isl/union_set.h>
31 #include <isl/union_map.h>
32 #include <isl/schedule.h>
35 #include <isl/options.h>
39 #include "coretypes.h"
44 #include "fold-const.h"
45 #include "gimple-iterator.h"
46 #include "tree-ssa-loop.h"
48 #include "tree-data-ref.h"
49 #include "graphite-poly.h"
53 static isl_union_set
*
54 scop_get_domains (scop_p scop ATTRIBUTE_UNUSED
)
58 isl_space
*space
= isl_set_get_space (scop
->context
);
59 isl_union_set
*res
= isl_union_set_empty (space
);
61 FOR_EACH_VEC_ELT (scop
->bbs
, i
, pbb
)
62 res
= isl_union_set_add_set (res
, isl_set_copy (pbb
->domain
));
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.
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}
81 for (i = 0; i < N; i++)
82 for (j = 0; j < M; j++)
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
94 static isl_basic_map
*
95 get_tile_map (isl_ctx
*ctx
, int schedule_dimensions
, int tile_size
)
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. */
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
++)
114 int pX
= schedule_dimensions
+ x
;
115 int aX
= 2 * schedule_dimensions
+ x
;
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
);
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
);
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
149 This reduces the number of visible scattering dimensions and allows isl
150 to produces better code. */
152 isl_basic_map_project_out (tile_map
, isl_dim_out
,
153 2 * schedule_dimensions
, schedule_dimensions
);
154 isl_local_space_free (local_space
);
158 /* get_schedule_for_band - Get the schedule for this BAND.
160 Polly applies transformations like tiling on top of the isl calculated
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
;
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
)
212 isl_union_map
*schedule
;
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
++)
222 isl_union_map
*partial_schedule
;
223 int schedule_dimensions
;
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
);
236 = isl_union_map_flat_range_product (partial_schedule
,
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
);
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
);
260 get_single_map (__isl_take isl_map
*map
, void *user
)
262 isl_map
**single_map
= (isl_map
**)user
;
268 apply_schedule_map_to_scop (scop_p scop
, isl_union_map
*schedule_map
)
273 FOR_EACH_VEC_ELT (scop
->bbs
, 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. */
294 optimize_isl (scop_p scop
)
296 #ifdef HAVE_ISL_CTX_MAX_OPERATIONS
297 int old_max_operations
= isl_ctx_get_max_operations (scop
->ctx
);
298 int max_operations
= PARAM_VALUE (PARAM_MAX_ISL_OPERATIONS
);
300 isl_ctx_set_max_operations (scop
->ctx
, max_operations
);
302 isl_options_set_on_error (scop
->ctx
, ISL_ON_ERROR_CONTINUE
);
304 isl_union_set
*domain
= scop_get_domains (scop
);
305 isl_union_map
*dependences
= scop_get_dependences (scop
);
307 = isl_union_map_gist_domain (dependences
, isl_union_set_copy (domain
));
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
);
317 = isl_schedule_constraints_set_proximity (schedule_constraints
,
320 = isl_schedule_constraints_set_validity (schedule_constraints
,
321 isl_union_map_copy (validity
));
323 = isl_schedule_constraints_set_coincidence (schedule_constraints
,
327 isl_options_set_schedule_max_constant_term (scop
->ctx
, CONSTANT_BOUND
);
328 isl_options_set_schedule_maximize_band_depth (scop
->ctx
, 1);
329 #ifdef HAVE_ISL_OPTIONS_SET_SCHEDULE_SERIALIZE_SCCS
330 isl_options_set_schedule_serialize_sccs (scop
->ctx
, 1);
332 isl_options_set_schedule_fuse (scop
->ctx
, ISL_SCHEDULE_FUSE_MIN
);
335 #ifdef HAVE_ISL_SCHED_CONSTRAINTS_COMPUTE_SCHEDULE
336 isl_schedule
*schedule
337 = isl_schedule_constraints_compute_schedule (schedule_constraints
);
339 isl_schedule
*schedule
340 = isl_union_set_compute_schedule (domain
, validity
, proximity
);
343 isl_options_set_on_error (scop
->ctx
, ISL_ON_ERROR_ABORT
);
345 #ifdef HAVE_ISL_CTX_MAX_OPERATIONS
346 isl_ctx_reset_operations (scop
->ctx
);
347 isl_ctx_set_max_operations (scop
->ctx
, old_max_operations
);
348 if (!schedule
|| isl_ctx_last_error (scop
->ctx
) == isl_error_quota
)
350 if (dump_file
&& dump_flags
)
351 fprintf (dump_file
, "ISL timed out at %d operations\n",
354 isl_schedule_free (schedule
);
362 isl_union_map
*schedule_map
= get_schedule_map (schedule
);
363 apply_schedule_map_to_scop (scop
, schedule_map
);
365 isl_schedule_free (schedule
);
366 isl_union_map_free (schedule_map
);
370 #endif /* HAVE_isl */