PR rtl-optimization/82913
[official-gcc.git] / gcc / graphite-dependences.c
blobbd3e91ba86088ecc530f2098a26410fe0c96f6c4
1 /* Data dependence analysis for Graphite.
2 Copyright (C) 2009-2017 Free Software Foundation, Inc.
3 Contributed by Sebastian Pop <sebastian.pop@amd.com> and
4 Konrad Trifunovic <konrad.trifunovic@inria.fr>.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 #define USES_ISL
24 #include "config.h"
26 #ifdef HAVE_isl
28 #include "system.h"
29 #include "coretypes.h"
30 #include "backend.h"
31 #include "cfghooks.h"
32 #include "tree.h"
33 #include "gimple.h"
34 #include "fold-const.h"
35 #include "gimple-iterator.h"
36 #include "tree-ssa-loop.h"
37 #include "tree-pass.h"
38 #include "cfgloop.h"
39 #include "tree-data-ref.h"
40 #include "graphite.h"
42 /* Add the constraints from the set S to the domain of MAP. */
44 static isl_map *
45 constrain_domain (isl_map *map, isl_set *s)
47 isl_space *d = isl_map_get_space (map);
48 isl_id *id = isl_space_get_tuple_id (d, isl_dim_in);
50 s = isl_set_set_tuple_id (s, id);
51 isl_space_free (d);
52 return isl_map_coalesce (isl_map_intersect_domain (map, s));
55 /* Constrain pdr->accesses with pdr->subscript_sizes and pbb->domain. */
57 static isl_map *
58 add_pdr_constraints (poly_dr_p pdr, poly_bb_p pbb)
60 isl_map *x = isl_map_intersect_range (isl_map_copy (pdr->accesses),
61 isl_set_copy (pdr->subscript_sizes));
62 x = isl_map_coalesce (x);
63 return constrain_domain (x, isl_set_copy (pbb->domain));
66 /* Returns an isl description of all memory operations in SCOP. The memory
67 reads are returned in READS and writes in MUST_WRITES and MAY_WRITES. */
69 static void
70 scop_get_reads_and_writes (scop_p scop, isl_union_map *&reads,
71 isl_union_map *&must_writes,
72 isl_union_map *&may_writes)
74 int i, j;
75 poly_bb_p pbb;
76 poly_dr_p pdr;
78 FOR_EACH_VEC_ELT (scop->pbbs, i, pbb)
80 FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr) {
81 if (pdr_read_p (pdr))
83 if (dump_file)
85 fprintf (dump_file, "Adding read to depedence graph: ");
86 print_pdr (dump_file, pdr);
88 isl_union_map *um
89 = isl_union_map_from_map (add_pdr_constraints (pdr, pbb));
90 reads = isl_union_map_union (reads, um);
91 if (dump_file)
93 fprintf (dump_file, "Reads depedence graph: ");
94 print_isl_union_map (dump_file, reads);
97 else if (pdr_write_p (pdr))
99 if (dump_file)
101 fprintf (dump_file, "Adding must write to depedence graph: ");
102 print_pdr (dump_file, pdr);
104 isl_union_map *um
105 = isl_union_map_from_map (add_pdr_constraints (pdr, pbb));
106 must_writes = isl_union_map_union (must_writes, um);
107 if (dump_file)
109 fprintf (dump_file, "Must writes depedence graph: ");
110 print_isl_union_map (dump_file, must_writes);
113 else if (pdr_may_write_p (pdr))
115 if (dump_file)
117 fprintf (dump_file, "Adding may write to depedence graph: ");
118 print_pdr (dump_file, pdr);
120 isl_union_map *um
121 = isl_union_map_from_map (add_pdr_constraints (pdr, pbb));
122 may_writes = isl_union_map_union (may_writes, um);
123 if (dump_file)
125 fprintf (dump_file, "May writes depedence graph: ");
126 print_isl_union_map (dump_file, may_writes);
133 /* Helper function used on each MAP of a isl_union_map. Computes the
134 maximal output dimension. */
136 static isl_stat
137 max_number_of_out_dimensions (__isl_take isl_map *map, void *user)
139 int global_max = *((int *) user);
140 isl_space *space = isl_map_get_space (map);
141 int nb_out = isl_space_dim (space, isl_dim_out);
143 if (global_max < nb_out)
144 *((int *) user) = nb_out;
146 isl_map_free (map);
147 isl_space_free (space);
148 return isl_stat_ok;
151 /* Extends the output dimension of MAP to MAX dimensions. */
153 static __isl_give isl_map *
154 extend_map (__isl_take isl_map *map, int max)
156 isl_space *space = isl_map_get_space (map);
157 int n = isl_space_dim (space, isl_dim_out);
159 isl_space_free (space);
160 return isl_map_add_dims (map, isl_dim_out, max - n);
163 /* Structure used to pass parameters to extend_schedule_1. */
165 struct extend_schedule_str {
166 int max;
167 isl_union_map *umap;
170 /* Helper function for extend_schedule. */
172 static isl_stat
173 extend_schedule_1 (__isl_take isl_map *map, void *user)
175 struct extend_schedule_str *str = (struct extend_schedule_str *) user;
176 str->umap = isl_union_map_add_map (str->umap, extend_map (map, str->max));
177 return isl_stat_ok;
180 /* Return a relation that has uniform output dimensions. */
182 static __isl_give isl_union_map *
183 extend_schedule (__isl_take isl_union_map *x)
185 int max = 0;
186 struct extend_schedule_str str;
188 isl_union_map_foreach_map (x, max_number_of_out_dimensions, (void *) &max);
189 str.max = max;
190 str.umap = isl_union_map_empty (isl_union_map_get_space (x));
191 isl_union_map_foreach_map (x, extend_schedule_1, (void *) &str);
192 isl_union_map_free (x);
193 return isl_union_map_coalesce (str.umap);
196 /* Applies SCHEDULE to the in and out dimensions of the dependences
197 DEPS and return the resulting relation. */
199 static isl_map *
200 apply_schedule_on_deps (__isl_keep isl_union_map *schedule,
201 __isl_keep isl_union_map *deps)
203 isl_union_map *trans = extend_schedule (isl_union_map_copy (schedule));
204 isl_union_map *ux = isl_union_map_copy (deps);
205 ux = isl_union_map_apply_domain (ux, isl_union_map_copy (trans));
206 ux = isl_union_map_apply_range (ux, trans);
207 ux = isl_union_map_coalesce (ux);
209 if (!isl_union_map_is_empty (ux))
210 return isl_map_from_union_map (ux);
212 isl_union_map_free (ux);
213 return NULL;
216 /* Return true when DEPS is non empty and the intersection of LEX with
217 the DEPS transformed by SCHEDULE is non empty. LEX is the relation
218 in which all the inputs before DEPTH occur at the same time as the
219 output, and the input at DEPTH occurs before output. */
221 bool
222 carries_deps (__isl_keep isl_union_map *schedule,
223 __isl_keep isl_union_map *deps,
224 int depth)
226 if (isl_union_map_is_empty (deps))
227 return false;
229 isl_map *x = apply_schedule_on_deps (schedule, deps);
230 if (x == NULL)
231 return false;
233 isl_space *space = isl_map_get_space (x);
234 isl_map *lex = isl_map_lex_le (isl_space_range (space));
235 isl_constraint *ineq = isl_inequality_alloc
236 (isl_local_space_from_space (isl_map_get_space (x)));
238 for (int i = 0; i < depth - 1; i++)
239 lex = isl_map_equate (lex, isl_dim_in, i, isl_dim_out, i);
241 /* in + 1 <= out */
242 ineq = isl_constraint_set_coefficient_si (ineq, isl_dim_out, depth - 1, 1);
243 ineq = isl_constraint_set_coefficient_si (ineq, isl_dim_in, depth - 1, -1);
244 ineq = isl_constraint_set_constant_si (ineq, -1);
245 lex = isl_map_add_constraint (lex, ineq);
246 lex = isl_map_coalesce (lex);
247 x = isl_map_intersect (x, lex);
248 bool res = !isl_map_is_empty (x);
250 isl_map_free (x);
251 return res;
254 /* Compute the dependence relations for the SCOP:
255 RAW are read after write dependences,
256 WAR are write after read dependences,
257 WAW are write after write dependences. */
259 void
260 scop_get_dependences (scop_p scop)
262 if (scop->dependence)
263 return;
265 isl_space *space = isl_set_get_space (scop->param_context);
266 isl_union_map *reads = isl_union_map_empty (isl_space_copy (space));
267 isl_union_map *must_writes = isl_union_map_empty (isl_space_copy (space));
268 isl_union_map *may_writes = isl_union_map_empty (space);
269 scop_get_reads_and_writes (scop, reads, must_writes, may_writes);
271 if (dump_file)
273 fprintf (dump_file, "\n--- Documentation for datarefs dump: ---\n");
274 fprintf (dump_file, "Statements on the iteration domain are mapped to"
275 " array references.\n");
276 fprintf (dump_file, " To read the following data references:\n\n");
277 fprintf (dump_file, " S_5[i0] -> [106] : i0 >= 0 and i0 <= 3\n");
278 fprintf (dump_file, " S_8[i0] -> [1, i0] : i0 >= 0 and i0 <= 3\n\n");
280 fprintf (dump_file, " S_5[i0] is the dynamic instance of statement"
281 " bb_5 in a loop that accesses all iterations 0 <= i0 <= 3.\n");
282 fprintf (dump_file, " [1, i0] is a 'memref' with alias set 1"
283 " and first subscript access i0.\n");
284 fprintf (dump_file, " [106] is a 'scalar reference' which is the sum of"
285 " SSA_NAME_VERSION 6"
286 " and --param graphite-max-arrays-per-scop=100\n");
287 fprintf (dump_file, "-----------------------\n\n");
289 fprintf (dump_file, "data references (\n");
290 fprintf (dump_file, " reads: ");
291 print_isl_union_map (dump_file, reads);
292 fprintf (dump_file, " must_writes: ");
293 print_isl_union_map (dump_file, must_writes);
294 fprintf (dump_file, " may_writes: ");
295 print_isl_union_map (dump_file, may_writes);
296 fprintf (dump_file, ")\n");
299 gcc_assert (scop->original_schedule);
301 isl_union_access_info *ai;
302 ai = isl_union_access_info_from_sink (isl_union_map_copy (reads));
303 ai = isl_union_access_info_set_must_source (ai, isl_union_map_copy (must_writes));
304 ai = isl_union_access_info_set_may_source (ai, may_writes);
305 ai = isl_union_access_info_set_schedule
306 (ai, isl_schedule_copy (scop->original_schedule));
307 isl_union_flow *flow = isl_union_access_info_compute_flow (ai);
308 isl_union_map *raw = isl_union_flow_get_must_dependence (flow);
309 isl_union_flow_free (flow);
311 ai = isl_union_access_info_from_sink (isl_union_map_copy (must_writes));
312 ai = isl_union_access_info_set_must_source (ai, must_writes);
313 ai = isl_union_access_info_set_may_source (ai, reads);
314 ai = isl_union_access_info_set_schedule
315 (ai, isl_schedule_copy (scop->original_schedule));
316 flow = isl_union_access_info_compute_flow (ai);
318 isl_union_map *waw = isl_union_flow_get_must_dependence (flow);
319 isl_union_map *war = isl_union_flow_get_may_dependence (flow);
320 war = isl_union_map_subtract (war, isl_union_map_copy (waw));
321 isl_union_flow_free (flow);
323 raw = isl_union_map_coalesce (raw);
324 waw = isl_union_map_coalesce (waw);
325 war = isl_union_map_coalesce (war);
327 isl_union_map *dependences = raw;
328 dependences = isl_union_map_union (dependences, war);
329 dependences = isl_union_map_union (dependences, waw);
330 dependences = isl_union_map_coalesce (dependences);
332 if (dump_file)
334 fprintf (dump_file, "data dependences (\n");
335 print_isl_union_map (dump_file, dependences);
336 fprintf (dump_file, ")\n");
339 scop->dependence = dependences;
342 #endif /* HAVE_isl */