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/>. */
28 #include "coretypes.h"
33 #include "fold-const.h"
34 #include "gimple-iterator.h"
35 #include "tree-ssa-loop.h"
37 #include "tree-data-ref.h"
41 #include <isl/constraint.h>
43 #include <isl/union_set.h>
45 #include <isl/union_map.h>
46 #include <isl/schedule.h>
49 #include <isl/options.h>
51 #ifdef HAVE_ISL_OPTIONS_SET_SCHEDULE_SERIALIZE_SCCS
52 #include <isl/schedule_node.h>
53 #include <isl/ast_build.h>
58 #ifdef HAVE_ISL_OPTIONS_SET_SCHEDULE_SERIALIZE_SCCS
60 /* get_schedule_for_node_st - Improve schedule for the schedule node.
61 Only Simple loop tiling is considered. */
63 static __isl_give isl_schedule_node
*
64 get_schedule_for_node_st (__isl_take isl_schedule_node
*node
, void *user
)
69 if (isl_schedule_node_get_type (node
) != isl_schedule_node_band
70 || isl_schedule_node_n_children (node
) != 1)
73 isl_space
*space
= isl_schedule_node_band_get_space (node
);
74 unsigned dims
= isl_space_dim (space
, isl_dim_set
);
75 isl_schedule_node
*child
= isl_schedule_node_get_child (node
, 0);
76 isl_schedule_node_type type
= isl_schedule_node_get_type (child
);
77 isl_space_free (space
);
78 isl_schedule_node_free (child
);
80 if (type
!= isl_schedule_node_leaf
)
83 if (dims
<= 1 || !isl_schedule_node_band_get_permutable (node
))
85 if (dump_file
&& dump_flags
)
86 fprintf (dump_file
, "not tiled\n");
91 space
= isl_schedule_node_band_get_space (node
);
92 isl_multi_val
*sizes
= isl_multi_val_zero (space
);
93 long tile_size
= PARAM_VALUE (PARAM_LOOP_BLOCK_TILE_SIZE
);
94 isl_ctx
*ctx
= isl_schedule_node_get_ctx (node
);
96 for (unsigned i
= 0; i
< dims
; i
++)
98 sizes
= isl_multi_val_set_val (sizes
, i
,
99 isl_val_int_from_si (ctx
, tile_size
));
100 if (dump_file
&& dump_flags
)
101 fprintf (dump_file
, "tiled by %ld\n", tile_size
);
104 node
= isl_schedule_node_band_tile (node
, sizes
);
105 node
= isl_schedule_node_child (node
, 0);
110 /* get_schedule_map_st - Improve the schedule by performing other loop
111 optimizations. _st ending is for schedule tree version of this
112 function (see get_schedule_map below for the band forest version).
114 Do a depth-first post-order traversal of the nodes in a schedule
115 tree and apply get_schedule_for_node_st on them to improve the schedule.
118 static __isl_give isl_union_map
*
119 get_schedule_map_st (__isl_keep isl_schedule
*schedule
)
122 schedule
= isl_schedule_map_schedule_node_bottom_up (schedule
,
123 get_schedule_for_node_st
,
125 isl_union_map
*schedule_map
= isl_schedule_get_map (schedule
);
130 /* get_tile_map - Create a map that describes a n-dimensonal tiling.
132 get_tile_map creates a map from a n-dimensional scattering space into an
133 2*n-dimensional scattering space. The map describes a rectangular tiling.
136 SCHEDULE_DIMENSIONS = 2, PARAMETER_DIMENSIONS = 1, TILE_SIZE = 32
138 tile_map := [p0] -> {[s0, s1] -> [t0, t1, s0, s1]:
139 t0 % 32 = 0 and t0 <= s0 < t0 + 32 and
140 t1 % 32 = 0 and t1 <= s1 < t1 + 32}
144 for (i = 0; i < N; i++)
145 for (j = 0; j < M; j++)
150 for (t_i = 0; t_i < N; i+=32)
151 for (t_j = 0; t_j < M; j+=32)
152 for (i = t_i; i < min(t_i + 32, N); i++) | Unknown that N % 32 = 0
153 for (j = t_j; j < t_j + 32; j++) | Known that M % 32 = 0
157 static isl_basic_map
*
158 get_tile_map (isl_ctx
*ctx
, int schedule_dimensions
, int tile_size
)
162 tile_map := [p0] -> {[s0, s1] -> [t0, t1, p0, p1, a0, a1]:
163 s0 = a0 * 32 and s0 = p0 and t0 <= p0 < t0 + 32 and
164 s1 = a1 * 32 and s1 = p1 and t1 <= p1 < t1 + 32}
166 and project out the auxilary dimensions a0 and a1. */
168 = isl_space_alloc (ctx
, 0, schedule_dimensions
, schedule_dimensions
* 3);
169 isl_basic_map
*tile_map
= isl_basic_map_universe (isl_space_copy (space
));
171 isl_local_space
*local_space
= isl_local_space_from_space (space
);
173 for (int x
= 0; x
< schedule_dimensions
; x
++)
177 int pX
= schedule_dimensions
+ x
;
178 int aX
= 2 * schedule_dimensions
+ x
;
182 /* sX = aX * tile_size; */
183 c
= isl_equality_alloc (isl_local_space_copy (local_space
));
184 isl_constraint_set_coefficient_si (c
, isl_dim_out
, sX
, 1);
185 isl_constraint_set_coefficient_si (c
, isl_dim_out
, aX
, -tile_size
);
186 tile_map
= isl_basic_map_add_constraint (tile_map
, c
);
189 c
= isl_equality_alloc (isl_local_space_copy (local_space
));
190 isl_constraint_set_coefficient_si (c
, isl_dim_out
, pX
, 1);
191 isl_constraint_set_coefficient_si (c
, isl_dim_in
, sX
, -1);
192 tile_map
= isl_basic_map_add_constraint (tile_map
, c
);
195 c
= isl_inequality_alloc (isl_local_space_copy (local_space
));
196 isl_constraint_set_coefficient_si (c
, isl_dim_out
, pX
, 1);
197 isl_constraint_set_coefficient_si (c
, isl_dim_out
, tX
, -1);
198 tile_map
= isl_basic_map_add_constraint (tile_map
, c
);
200 /* pX <= tX + (tile_size - 1) */
201 c
= isl_inequality_alloc (isl_local_space_copy (local_space
));
202 isl_constraint_set_coefficient_si (c
, isl_dim_out
, tX
, 1);
203 isl_constraint_set_coefficient_si (c
, isl_dim_out
, pX
, -1);
204 isl_constraint_set_constant_si (c
, tile_size
- 1);
205 tile_map
= isl_basic_map_add_constraint (tile_map
, c
);
208 /* Project out auxiliary dimensions.
210 The auxiliary dimensions are transformed into existentially quantified
212 This reduces the number of visible scattering dimensions and allows isl
213 to produces better code. */
215 isl_basic_map_project_out (tile_map
, isl_dim_out
,
216 2 * schedule_dimensions
, schedule_dimensions
);
217 isl_local_space_free (local_space
);
221 /* get_schedule_for_band - Get the schedule for this BAND.
223 Polly applies transformations like tiling on top of the isl calculated
225 This can influence the number of scheduling dimension. The number of
226 schedule dimensions is returned in DIMENSIONS. */
228 static isl_union_map
*
229 get_schedule_for_band (isl_band
*band
, int *dimensions
)
231 isl_union_map
*partial_schedule
;
234 isl_basic_map
*tile_map
;
235 isl_union_map
*tile_umap
;
237 partial_schedule
= isl_band_get_partial_schedule (band
);
238 *dimensions
= isl_band_n_member (band
);
240 /* It does not make any sense to tile a band with just one dimension. */
241 if (*dimensions
== 1)
243 if (dump_file
&& dump_flags
)
244 fprintf (dump_file
, "not tiled\n");
245 return partial_schedule
;
248 if (dump_file
&& dump_flags
)
249 fprintf (dump_file
, "tiled by %d\n",
250 PARAM_VALUE (PARAM_LOOP_BLOCK_TILE_SIZE
));
252 ctx
= isl_union_map_get_ctx (partial_schedule
);
253 space
= isl_union_map_get_space (partial_schedule
);
255 tile_map
= get_tile_map (ctx
, *dimensions
,
256 PARAM_VALUE (PARAM_LOOP_BLOCK_TILE_SIZE
));
257 tile_umap
= isl_union_map_from_map (isl_map_from_basic_map (tile_map
));
258 tile_umap
= isl_union_map_align_params (tile_umap
, space
);
259 *dimensions
= 2 * *dimensions
;
261 return isl_union_map_apply_range (partial_schedule
, tile_umap
);
265 /* get_schedule_for_band_list - Get the scheduling map for a list of bands.
267 We walk recursively the forest of bands to combine the schedules of the
268 individual bands to the overall schedule. In case tiling is requested,
269 the individual bands are tiled. */
271 static isl_union_map
*
272 get_schedule_for_band_list (isl_band_list
*band_list
)
275 isl_union_map
*schedule
;
278 ctx
= isl_band_list_get_ctx (band_list
);
279 num_bands
= isl_band_list_n_band (band_list
);
280 schedule
= isl_union_map_empty (isl_space_params_alloc (ctx
, 0));
282 for (i
= 0; i
< num_bands
; i
++)
285 isl_union_map
*partial_schedule
;
286 int schedule_dimensions
;
289 band
= isl_band_list_get_band (band_list
, i
);
290 partial_schedule
= get_schedule_for_band (band
, &schedule_dimensions
);
291 space
= isl_union_map_get_space (partial_schedule
);
293 if (isl_band_has_children (band
))
295 isl_band_list
*children
= isl_band_get_children (band
);
296 isl_union_map
*suffixSchedule
297 = get_schedule_for_band_list (children
);
299 = isl_union_map_flat_range_product (partial_schedule
,
301 isl_band_list_free (children
);
304 schedule
= isl_union_map_union (schedule
, partial_schedule
);
306 isl_band_free (band
);
307 isl_space_free (space
);
313 static isl_union_map
*
314 get_schedule_map (isl_schedule
*schedule
)
316 isl_band_list
*bandList
= isl_schedule_get_band_forest (schedule
);
317 isl_union_map
*schedule_map
= get_schedule_for_band_list (bandList
);
318 isl_band_list_free (bandList
);
324 get_single_map (__isl_take isl_map
*map
, void *user
)
326 isl_map
**single_map
= (isl_map
**)user
;
332 apply_schedule_map_to_scop (scop_p scop
, isl_union_map
*schedule_map
)
337 FOR_EACH_VEC_ELT (scop
->pbbs
, i
, pbb
)
339 isl_set
*domain
= isl_set_copy (pbb
->domain
);
340 isl_map
*stmt_schedule
;
342 isl_union_map
*stmt_band
343 = isl_union_map_intersect_domain (isl_union_map_copy (schedule_map
),
344 isl_union_set_from_set (domain
));
345 isl_union_map_foreach_map (stmt_band
, get_single_map
, &stmt_schedule
);
346 isl_map_free (pbb
->transformed
);
347 pbb
->transformed
= stmt_schedule
;
348 isl_union_map_free (stmt_band
);
352 static isl_union_set
*
353 scop_get_domains (scop_p scop ATTRIBUTE_UNUSED
)
357 isl_space
*space
= isl_set_get_space (scop
->param_context
);
358 isl_union_set
*res
= isl_union_set_empty (space
);
360 FOR_EACH_VEC_ELT (scop
->pbbs
, i
, pbb
)
361 res
= isl_union_set_add_set (res
, isl_set_copy (pbb
->domain
));
366 static const int CONSTANT_BOUND
= 20;
368 /* Compute the schedule for SCOP based on its parameters, domain and set of
369 constraints. Then apply the schedule to SCOP. */
372 optimize_isl (scop_p scop
)
374 #ifdef HAVE_ISL_CTX_MAX_OPERATIONS
375 int old_max_operations
= isl_ctx_get_max_operations (scop
->isl_context
);
376 int max_operations
= PARAM_VALUE (PARAM_MAX_ISL_OPERATIONS
);
378 isl_ctx_set_max_operations (scop
->isl_context
, max_operations
);
380 isl_options_set_on_error (scop
->isl_context
, ISL_ON_ERROR_CONTINUE
);
382 isl_union_set
*domain
= scop_get_domains (scop
);
383 isl_union_map
*dependences
= scop_get_dependences (scop
);
385 = isl_union_map_gist_domain (dependences
, isl_union_set_copy (domain
));
387 = isl_union_map_gist_range (dependences
, isl_union_set_copy (domain
));
388 isl_union_map
*validity
= dependences
;
389 isl_union_map
*proximity
= isl_union_map_copy (validity
);
391 #ifdef HAVE_ISL_SCHED_CONSTRAINTS_COMPUTE_SCHEDULE
392 isl_schedule_constraints
*schedule_constraints
;
393 schedule_constraints
= isl_schedule_constraints_on_domain (domain
);
395 = isl_schedule_constraints_set_proximity (schedule_constraints
,
398 = isl_schedule_constraints_set_validity (schedule_constraints
,
399 isl_union_map_copy (validity
));
401 = isl_schedule_constraints_set_coincidence (schedule_constraints
,
405 isl_options_set_schedule_max_constant_term (scop
->isl_context
, CONSTANT_BOUND
);
406 isl_options_set_schedule_maximize_band_depth (scop
->isl_context
, 1);
407 #ifdef HAVE_ISL_OPTIONS_SET_SCHEDULE_SERIALIZE_SCCS
408 /* ISL-0.15 or later. */
409 isl_options_set_schedule_serialize_sccs (scop
->isl_context
, 0);
410 isl_options_set_schedule_maximize_band_depth (scop
->isl_context
, 1);
411 isl_options_set_schedule_max_constant_term (scop
->isl_context
, 20);
412 isl_options_set_schedule_max_coefficient (scop
->isl_context
, 20);
413 isl_options_set_tile_scale_tile_loops (scop
->isl_context
, 0);
414 isl_options_set_coalesce_bounded_wrapping (scop
->isl_context
, 1);
415 isl_options_set_ast_build_exploit_nested_bounds (scop
->isl_context
, 1);
416 isl_options_set_ast_build_atomic_upper_bound (scop
->isl_context
, 1);
418 isl_options_set_schedule_fuse (scop
->isl_context
, ISL_SCHEDULE_FUSE_MIN
);
421 #ifdef HAVE_ISL_SCHED_CONSTRAINTS_COMPUTE_SCHEDULE
422 isl_schedule
*schedule
423 = isl_schedule_constraints_compute_schedule (schedule_constraints
);
425 isl_schedule
*schedule
426 = isl_union_set_compute_schedule (domain
, validity
, proximity
);
429 isl_options_set_on_error (scop
->isl_context
, ISL_ON_ERROR_ABORT
);
431 #ifdef HAVE_ISL_CTX_MAX_OPERATIONS
432 isl_ctx_reset_operations (scop
->isl_context
);
433 isl_ctx_set_max_operations (scop
->isl_context
, old_max_operations
);
434 if (!schedule
|| isl_ctx_last_error (scop
->isl_context
) == isl_error_quota
)
436 if (dump_file
&& dump_flags
)
437 fprintf (dump_file
, "ISL timed out --param max-isl-operations=%d\n",
440 isl_schedule_free (schedule
);
448 #ifdef HAVE_ISL_OPTIONS_SET_SCHEDULE_SERIALIZE_SCCS
449 isl_union_map
*schedule_map
= get_schedule_map_st (schedule
);
451 isl_union_map
*schedule_map
= get_schedule_map (schedule
);
453 apply_schedule_map_to_scop (scop
, schedule_map
);
455 isl_schedule_free (schedule
);
456 isl_union_map_free (schedule_map
);
460 #endif /* HAVE_isl */