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