graphite-isl-ast-to-gimple.c: Add a new struct ast_build_info.
[platform/upstream/gcc.git] / gcc / graphite-optimize-isl.c
1 /* A scheduling optimizer for Graphite
2    Copyright (C) 2012-2014 Free Software Foundation, Inc.
3    Contributed by Tobias Grosser <tobias@grosser.es>.
4
5 This file is part of GCC.
6
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.
11
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.
16
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/>.  */
20
21 #include "config.h"
22
23 #ifdef HAVE_cloog
24 #include <isl/set.h>
25 #include <isl/map.h>
26 #include <isl/union_map.h>
27 #include <isl/schedule.h>
28 #include <isl/band.h>
29 #include <isl/aff.h>
30 #include <isl/options.h>
31 #endif
32
33 #include "system.h"
34 #include "coretypes.h"
35 #include "tree.h"
36 #include "basic-block.h"
37 #include "tree-ssa-alias.h"
38 #include "internal-fn.h"
39 #include "gimple-expr.h"
40 #include "is-a.h"
41 #include "gimple.h"
42 #include "gimple-iterator.h"
43 #include "tree-ssa-loop.h"
44 #include "dumpfile.h"
45 #include "cfgloop.h"
46 #include "tree-chrec.h"
47 #include "tree-data-ref.h"
48 #include "tree-scalar-evolution.h"
49 #include "sese.h"
50
51 #ifdef HAVE_cloog
52 #include "graphite-poly.h"
53
54 static isl_union_set *
55 scop_get_domains (scop_p scop ATTRIBUTE_UNUSED)
56 {
57   int i;
58   poly_bb_p pbb;
59   isl_space *space = isl_set_get_space (scop->context);
60   isl_union_set *res = isl_union_set_empty (space);
61
62   FOR_EACH_VEC_ELT (scop->bbs, i, pbb)
63     res = isl_union_set_add_set (res, isl_set_copy (pbb->domain));
64
65   return res;
66 }
67
68 /* getTileMap - Create a map that describes a n-dimensonal tiling.
69   
70    getTileMap creates a map from a n-dimensional scattering space into an
71    2*n-dimensional scattering space. The map describes a rectangular tiling.
72   
73    Example:
74      scheduleDimensions = 2, parameterDimensions = 1, tileSize = 32
75  
76     tileMap := [p0] -> {[s0, s1] -> [t0, t1, s0, s1]:
77                          t0 % 32 = 0 and t0 <= s0 < t0 + 32 and
78                          t1 % 32 = 0 and t1 <= s1 < t1 + 32}
79  
80    Before tiling:
81  
82    for (i = 0; i < N; i++)
83      for (j = 0; j < M; j++)
84         S(i,j)
85  
86    After tiling:
87  
88    for (t_i = 0; t_i < N; i+=32)
89      for (t_j = 0; t_j < M; j+=32)
90         for (i = t_i; i < min(t_i + 32, N); i++)  | Unknown that N % 32 = 0
91           for (j = t_j; j < t_j + 32; j++)        |   Known that M % 32 = 0
92             S(i,j)
93    */
94  
95 static isl_basic_map *
96 getTileMap (isl_ctx *ctx, int scheduleDimensions, int tileSize)
97 {
98   int x;
99   /* We construct
100
101      tileMap := [p0] -> {[s0, s1] -> [t0, t1, p0, p1, a0, a1]:
102                         s0 = a0 * 32 and s0 = p0 and t0 <= p0 < t0 + 32 and
103                         s1 = a1 * 32 and s1 = p1 and t1 <= p1 < t1 + 32}
104
105      and project out the auxilary dimensions a0 and a1.  */
106   isl_space *Space = isl_space_alloc (ctx, 0, scheduleDimensions,
107                                       scheduleDimensions * 3);
108   isl_basic_map *tileMap = isl_basic_map_universe (isl_space_copy (Space));
109
110   isl_local_space *LocalSpace = isl_local_space_from_space (Space);
111
112   for (x = 0; x < scheduleDimensions; x++)
113     {
114       int sX = x;
115       int tX = x;
116       int pX = scheduleDimensions + x;
117       int aX = 2 * scheduleDimensions + x;
118
119       isl_constraint *c;
120
121       /* sX = aX * tileSize; */
122       c = isl_equality_alloc (isl_local_space_copy (LocalSpace));
123       isl_constraint_set_coefficient_si (c, isl_dim_out, sX, 1);
124       isl_constraint_set_coefficient_si (c, isl_dim_out, aX, -tileSize);
125       tileMap = isl_basic_map_add_constraint (tileMap, c);
126
127       /* pX = sX; */
128       c = isl_equality_alloc (isl_local_space_copy (LocalSpace));
129       isl_constraint_set_coefficient_si (c, isl_dim_out, pX, 1);
130       isl_constraint_set_coefficient_si (c, isl_dim_in, sX, -1);
131       tileMap = isl_basic_map_add_constraint (tileMap, c);
132
133       /* tX <= pX */
134       c = isl_inequality_alloc (isl_local_space_copy (LocalSpace));
135       isl_constraint_set_coefficient_si (c, isl_dim_out, pX, 1);
136       isl_constraint_set_coefficient_si (c, isl_dim_out, tX, -1);
137       tileMap = isl_basic_map_add_constraint (tileMap, c);
138
139       /* pX <= tX + (tileSize - 1) */
140       c = isl_inequality_alloc (isl_local_space_copy (LocalSpace));
141       isl_constraint_set_coefficient_si (c, isl_dim_out, tX, 1);
142       isl_constraint_set_coefficient_si (c, isl_dim_out, pX, -1);
143       isl_constraint_set_constant_si (c, tileSize - 1);
144       tileMap = isl_basic_map_add_constraint (tileMap, c);
145     }
146
147   /* Project out auxiliary dimensions.
148
149      The auxiliary dimensions are transformed into existentially quantified ones.
150      This reduces the number of visible scattering dimensions and allows Cloog
151      to produces better code.  */
152   tileMap = isl_basic_map_project_out (tileMap, isl_dim_out,
153                                        2 * scheduleDimensions,
154                                        scheduleDimensions);
155   isl_local_space_free (LocalSpace);
156   return tileMap;
157 }
158
159 /* getScheduleForBand - Get the schedule for this band.
160   
161    Polly applies transformations like tiling on top of the isl calculated value.
162    This can influence the number of scheduling dimension. The number of
163    schedule dimensions is returned in the parameter 'Dimension'.  */
164 static bool DisableTiling = false;
165
166 static isl_union_map *
167 getScheduleForBand (isl_band *Band, int *Dimensions)
168 {
169   isl_union_map *PartialSchedule;
170   isl_ctx *ctx;
171   isl_space *Space;
172   isl_basic_map *TileMap;
173   isl_union_map *TileUMap;
174
175   PartialSchedule = isl_band_get_partial_schedule (Band);
176   *Dimensions = isl_band_n_member (Band);
177
178   if (DisableTiling)
179     return PartialSchedule;
180
181   /* It does not make any sense to tile a band with just one dimension.  */
182   if (*Dimensions == 1)
183     return PartialSchedule;
184
185   ctx = isl_union_map_get_ctx (PartialSchedule);
186   Space = isl_union_map_get_space (PartialSchedule);
187
188   TileMap = getTileMap (ctx, *Dimensions, 32);
189   TileUMap = isl_union_map_from_map (isl_map_from_basic_map (TileMap));
190   TileUMap = isl_union_map_align_params (TileUMap, Space);
191   *Dimensions = 2 * *Dimensions;
192
193   return isl_union_map_apply_range (PartialSchedule, TileUMap);
194 }
195
196 /* Create a map that pre-vectorizes one scheduling dimension.
197   
198    getPrevectorMap creates a map that maps each input dimension to the same
199    output dimension, except for the dimension DimToVectorize. DimToVectorize is
200    strip mined by 'VectorWidth' and the newly created point loop of
201    DimToVectorize is moved to the innermost level.
202   
203    Example (DimToVectorize=0, ScheduleDimensions=2, VectorWidth=4):
204   
205    | Before transformation
206    |
207    | A[i,j] -> [i,j]
208    |
209    | for (i = 0; i < 128; i++)
210    |    for (j = 0; j < 128; j++)
211    |      A(i,j);
212   
213      Prevector map:
214      [i,j] -> [it,j,ip] : it % 4 = 0 and it <= ip <= it + 3 and i = ip
215   
216    | After transformation:
217    |
218    | A[i,j] -> [it,j,ip] : it % 4 = 0 and it <= ip <= it + 3 and i = ip
219    |
220    | for (it = 0; it < 128; it+=4)
221    |    for (j = 0; j < 128; j++)
222    |      for (ip = max(0,it); ip < min(128, it + 3); ip++)
223    |        A(ip,j);
224   
225    The goal of this transformation is to create a trivially vectorizable loop.
226    This means a parallel loop at the innermost level that has a constant number
227    of iterations corresponding to the target vector width.
228   
229    This transformation creates a loop at the innermost level. The loop has a
230    constant number of iterations, if the number of loop iterations at
231    DimToVectorize can be devided by VectorWidth. The default VectorWidth is
232    currently constant and not yet target specific. This function does not reason
233    about parallelism.  */
234 static isl_map *
235 getPrevectorMap (isl_ctx *ctx, int DimToVectorize,
236                  int ScheduleDimensions,
237                  int VectorWidth)
238 {
239   isl_space *Space;
240   isl_local_space *LocalSpace, *LocalSpaceRange;
241   isl_set *Modulo;
242   isl_map *TilingMap;
243   isl_constraint *c;
244   isl_aff *Aff;
245   int PointDimension; /* ip */
246   int TileDimension;  /* it */
247   isl_int VectorWidthMP;
248   int i;
249
250   /* assert (0 <= DimToVectorize && DimToVectorize < ScheduleDimensions);*/
251
252   Space = isl_space_alloc (ctx, 0, ScheduleDimensions, ScheduleDimensions + 1);
253   TilingMap = isl_map_universe (isl_space_copy (Space));
254   LocalSpace = isl_local_space_from_space (Space);
255   PointDimension = ScheduleDimensions;
256   TileDimension = DimToVectorize;
257
258   /* Create an identity map for everything except DimToVectorize and map
259      DimToVectorize to the point loop at the innermost dimension.  */
260   for (i = 0; i < ScheduleDimensions; i++)
261     {
262       c = isl_equality_alloc (isl_local_space_copy (LocalSpace));
263       isl_constraint_set_coefficient_si (c, isl_dim_in, i, -1);
264
265       if (i == DimToVectorize)
266         isl_constraint_set_coefficient_si (c, isl_dim_out, PointDimension, 1);
267       else
268         isl_constraint_set_coefficient_si (c, isl_dim_out, i, 1);
269
270       TilingMap = isl_map_add_constraint (TilingMap, c);
271     }
272
273   /* it % 'VectorWidth' = 0  */
274   LocalSpaceRange = isl_local_space_range (isl_local_space_copy (LocalSpace));
275   Aff = isl_aff_zero_on_domain (LocalSpaceRange);
276   Aff = isl_aff_set_constant_si (Aff, VectorWidth);
277   Aff = isl_aff_set_coefficient_si (Aff, isl_dim_in, TileDimension, 1);
278   isl_int_init (VectorWidthMP);
279   isl_int_set_si (VectorWidthMP, VectorWidth);
280   Aff = isl_aff_mod (Aff, VectorWidthMP);
281   isl_int_clear (VectorWidthMP);
282   Modulo = isl_pw_aff_zero_set (isl_pw_aff_from_aff (Aff));
283   TilingMap = isl_map_intersect_range (TilingMap, Modulo);
284
285   /* it <= ip */
286   c = isl_inequality_alloc (isl_local_space_copy (LocalSpace));
287   isl_constraint_set_coefficient_si (c, isl_dim_out, TileDimension, -1);
288   isl_constraint_set_coefficient_si (c, isl_dim_out, PointDimension, 1);
289   TilingMap = isl_map_add_constraint (TilingMap, c);
290
291   /* ip <= it + ('VectorWidth' - 1) */
292   c = isl_inequality_alloc (LocalSpace);
293   isl_constraint_set_coefficient_si (c, isl_dim_out, TileDimension, 1);
294   isl_constraint_set_coefficient_si (c, isl_dim_out, PointDimension, -1);
295   isl_constraint_set_constant_si (c, VectorWidth - 1);
296   TilingMap = isl_map_add_constraint (TilingMap, c);
297
298   isl_map_dump (TilingMap);
299
300   return TilingMap;
301 }
302
303 static bool EnablePollyVector = false;
304
305 /* getScheduleForBandList - Get the scheduling map for a list of bands.
306     
307    We walk recursively the forest of bands to combine the schedules of the
308    individual bands to the overall schedule. In case tiling is requested,
309    the individual bands are tiled.  */
310 static isl_union_map *
311 getScheduleForBandList (isl_band_list *BandList)
312 {
313   int NumBands, i;
314   isl_union_map *Schedule;
315   isl_ctx *ctx;
316
317   ctx = isl_band_list_get_ctx (BandList);
318   NumBands = isl_band_list_n_band (BandList);
319   Schedule = isl_union_map_empty (isl_space_params_alloc (ctx, 0));
320
321   for (i = 0; i < NumBands; i++)
322     {
323       isl_band *Band;
324       isl_union_map *PartialSchedule;
325       int ScheduleDimensions;
326       isl_space *Space;
327
328       Band = isl_band_list_get_band (BandList, i);
329       PartialSchedule = getScheduleForBand (Band, &ScheduleDimensions);
330       Space = isl_union_map_get_space (PartialSchedule);
331
332       if (isl_band_has_children (Band))
333         {
334           isl_band_list *Children;
335           isl_union_map *SuffixSchedule;
336
337           Children = isl_band_get_children (Band);
338           SuffixSchedule = getScheduleForBandList (Children);
339           PartialSchedule = isl_union_map_flat_range_product (PartialSchedule,
340                                                               SuffixSchedule);
341           isl_band_list_free (Children);
342         }
343       else if (EnablePollyVector)
344         {
345           for (i = ScheduleDimensions - 1 ;  i >= 0 ; i--)
346             {
347               if (isl_band_member_is_zero_distance (Band, i))
348                 {
349                   isl_map *TileMap;
350                   isl_union_map *TileUMap;
351
352                   TileMap = getPrevectorMap (ctx, i, ScheduleDimensions, 4);
353                   TileUMap = isl_union_map_from_map (TileMap);
354                   TileUMap = isl_union_map_align_params
355                     (TileUMap, isl_space_copy (Space));
356                   PartialSchedule = isl_union_map_apply_range
357                     (PartialSchedule, TileUMap);
358                   break;
359                 }
360             }
361         }
362
363       Schedule = isl_union_map_union (Schedule, PartialSchedule);
364
365       isl_band_free (Band);
366       isl_space_free (Space);
367     }
368
369   return Schedule;
370 }
371
372 static isl_union_map *
373 getScheduleMap (isl_schedule *Schedule)
374 {
375   isl_band_list *BandList = isl_schedule_get_band_forest (Schedule);
376   isl_union_map *ScheduleMap = getScheduleForBandList (BandList);
377   isl_band_list_free (BandList);
378   return ScheduleMap;
379 }
380
381 static int
382 getSingleMap (__isl_take isl_map *map, void *user)
383 {
384   isl_map **singleMap = (isl_map **) user;
385   *singleMap = map;
386
387   return 0;
388 }
389
390 static void
391 apply_schedule_map_to_scop (scop_p scop, isl_union_map *schedule_map)
392 {
393   int i;
394   poly_bb_p pbb;
395
396   FOR_EACH_VEC_ELT (scop->bbs, i, pbb)
397     {
398       isl_set *domain = isl_set_copy (pbb->domain);
399       isl_union_map *stmtBand;
400       isl_map *stmtSchedule;
401
402       stmtBand = isl_union_map_intersect_domain
403         (isl_union_map_copy (schedule_map),
404          isl_union_set_from_set (domain));
405       isl_union_map_foreach_map (stmtBand, getSingleMap, &stmtSchedule);
406       isl_map_free (pbb->transformed);
407       pbb->transformed = stmtSchedule;
408       isl_union_map_free (stmtBand);
409     }
410 }
411
412 static const int CONSTANT_BOUND = 20;
413
414 bool
415 optimize_isl (scop_p scop)
416 {
417
418   isl_schedule *schedule;
419   isl_union_set *domain;
420   isl_union_map *validity, *proximity, *dependences;
421   isl_union_map *schedule_map;
422
423   domain = scop_get_domains (scop);
424   dependences = scop_get_dependences (scop);
425   dependences = isl_union_map_gist_domain (dependences,
426                                            isl_union_set_copy (domain));
427   dependences = isl_union_map_gist_range (dependences,
428                                           isl_union_set_copy (domain));
429   validity = dependences;
430
431   proximity = isl_union_map_copy (validity);
432
433   isl_options_set_schedule_max_constant_term (scop->ctx, CONSTANT_BOUND);
434   isl_options_set_schedule_maximize_band_depth (scop->ctx, 1);
435   isl_options_set_schedule_fuse (scop->ctx, ISL_SCHEDULE_FUSE_MIN);
436   isl_options_set_on_error (scop->ctx, ISL_ON_ERROR_CONTINUE);
437   schedule = isl_union_set_compute_schedule (domain, validity, proximity);
438   isl_options_set_on_error (scop->ctx, ISL_ON_ERROR_ABORT);
439
440   if (!schedule)
441     return false;
442
443   schedule_map = getScheduleMap (schedule);
444
445   apply_schedule_map_to_scop (scop, schedule_map);
446
447   isl_schedule_free (schedule);
448   isl_union_map_free (schedule_map);
449
450   return true;
451 }
452
453 #endif