]>
Commit | Line | Data |
---|---|---|
c6bb733d | 1 | /* Data dependence analysis for Graphite. |
fbd26352 | 2 | Copyright (C) 2009-2019 Free Software Foundation, Inc. |
c6bb733d | 3 | Contributed by Sebastian Pop <sebastian.pop@amd.com> and |
4 | Konrad Trifunovic <konrad.trifunovic@inria.fr>. | |
5 | ||
6 | This file is part of GCC. | |
7 | ||
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. | |
12 | ||
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. | |
17 | ||
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/>. */ | |
21 | ||
d8a2c81e | 22 | #define USES_ISL |
23 | ||
c6bb733d | 24 | #include "config.h" |
87e20041 | 25 | |
429cca51 | 26 | #ifdef HAVE_isl |
87e20041 | 27 | |
c6bb733d | 28 | #include "system.h" |
29 | #include "coretypes.h" | |
9ef16211 | 30 | #include "backend.h" |
d040a5b0 | 31 | #include "cfghooks.h" |
b20a8bb4 | 32 | #include "tree.h" |
9ef16211 | 33 | #include "gimple.h" |
9ef16211 | 34 | #include "fold-const.h" |
dcf1a1ec | 35 | #include "gimple-iterator.h" |
073c1fd5 | 36 | #include "tree-ssa-loop.h" |
f0a18dd2 | 37 | #include "tree-pass.h" |
c6bb733d | 38 | #include "cfgloop.h" |
c6bb733d | 39 | #include "tree-data-ref.h" |
39b8c5f3 | 40 | #include "graphite.h" |
0d6b5db2 | 41 | |
87e20041 | 42 | /* Add the constraints from the set S to the domain of MAP. */ |
c6bb733d | 43 | |
87e20041 | 44 | static isl_map * |
45 | constrain_domain (isl_map *map, isl_set *s) | |
0d6b5db2 | 46 | { |
87e20041 | 47 | isl_space *d = isl_map_get_space (map); |
48 | isl_id *id = isl_space_get_tuple_id (d, isl_dim_in); | |
a071b80b | 49 | |
87e20041 | 50 | s = isl_set_set_tuple_id (s, id); |
51 | isl_space_free (d); | |
ece4d5b1 | 52 | return isl_map_coalesce (isl_map_intersect_domain (map, s)); |
a071b80b | 53 | } |
54 | ||
fc25c670 | 55 | /* Constrain pdr->accesses with pdr->subscript_sizes and pbb->domain. */ |
a071b80b | 56 | |
87e20041 | 57 | static isl_map * |
58 | add_pdr_constraints (poly_dr_p pdr, poly_bb_p pbb) | |
a071b80b | 59 | { |
87e20041 | 60 | isl_map *x = isl_map_intersect_range (isl_map_copy (pdr->accesses), |
fc25c670 | 61 | isl_set_copy (pdr->subscript_sizes)); |
ece4d5b1 | 62 | x = isl_map_coalesce (x); |
63 | return constrain_domain (x, isl_set_copy (pbb->domain)); | |
a071b80b | 64 | } |
65 | ||
9c61da99 | 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. */ | |
a071b80b | 68 | |
9c61da99 | 69 | static void |
4a052765 | 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) | |
a071b80b | 73 | { |
87e20041 | 74 | int i, j; |
75 | poly_bb_p pbb; | |
76 | poly_dr_p pdr; | |
a071b80b | 77 | |
c1616982 | 78 | FOR_EACH_VEC_ELT (scop->pbbs, i, pbb) |
0d6b5db2 | 79 | { |
9c61da99 | 80 | FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr) { |
87e20041 | 81 | if (pdr_read_p (pdr)) |
fead8d0e | 82 | { |
83 | if (dump_file) | |
6fb10557 | 84 | { |
85 | fprintf (dump_file, "Adding read to depedence graph: "); | |
86 | print_pdr (dump_file, pdr); | |
87 | } | |
c1616982 | 88 | isl_union_map *um |
89 | = isl_union_map_from_map (add_pdr_constraints (pdr, pbb)); | |
9c61da99 | 90 | reads = isl_union_map_union (reads, um); |
6fb10557 | 91 | if (dump_file) |
92 | { | |
93 | fprintf (dump_file, "Reads depedence graph: "); | |
9c61da99 | 94 | print_isl_union_map (dump_file, reads); |
6fb10557 | 95 | } |
fead8d0e | 96 | } |
9c61da99 | 97 | else if (pdr_write_p (pdr)) |
fead8d0e | 98 | { |
99 | if (dump_file) | |
6fb10557 | 100 | { |
101 | fprintf (dump_file, "Adding must write to depedence graph: "); | |
102 | print_pdr (dump_file, pdr); | |
103 | } | |
c1616982 | 104 | isl_union_map *um |
105 | = isl_union_map_from_map (add_pdr_constraints (pdr, pbb)); | |
9c61da99 | 106 | must_writes = isl_union_map_union (must_writes, um); |
6fb10557 | 107 | if (dump_file) |
108 | { | |
109 | fprintf (dump_file, "Must writes depedence graph: "); | |
9c61da99 | 110 | print_isl_union_map (dump_file, must_writes); |
6fb10557 | 111 | } |
fead8d0e | 112 | } |
9c61da99 | 113 | else if (pdr_may_write_p (pdr)) |
fead8d0e | 114 | { |
115 | if (dump_file) | |
6fb10557 | 116 | { |
117 | fprintf (dump_file, "Adding may write to depedence graph: "); | |
118 | print_pdr (dump_file, pdr); | |
119 | } | |
c1616982 | 120 | isl_union_map *um |
121 | = isl_union_map_from_map (add_pdr_constraints (pdr, pbb)); | |
9c61da99 | 122 | may_writes = isl_union_map_union (may_writes, um); |
6fb10557 | 123 | if (dump_file) |
124 | { | |
125 | fprintf (dump_file, "May writes depedence graph: "); | |
9c61da99 | 126 | print_isl_union_map (dump_file, may_writes); |
6fb10557 | 127 | } |
fead8d0e | 128 | } |
9c61da99 | 129 | } |
abc97125 | 130 | } |
c6bb733d | 131 | } |
132 | ||
87e20041 | 133 | /* Helper function used on each MAP of a isl_union_map. Computes the |
134 | maximal output dimension. */ | |
f007fe97 | 135 | |
a26dad6a | 136 | static isl_stat |
87e20041 | 137 | max_number_of_out_dimensions (__isl_take isl_map *map, void *user) |
f007fe97 | 138 | { |
87e20041 | 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); | |
f007fe97 | 142 | |
87e20041 | 143 | if (global_max < nb_out) |
144 | *((int *) user) = nb_out; | |
f007fe97 | 145 | |
87e20041 | 146 | isl_map_free (map); |
147 | isl_space_free (space); | |
a26dad6a | 148 | return isl_stat_ok; |
f007fe97 | 149 | } |
150 | ||
87e20041 | 151 | /* Extends the output dimension of MAP to MAX dimensions. */ |
f007fe97 | 152 | |
87e20041 | 153 | static __isl_give isl_map * |
154 | extend_map (__isl_take isl_map *map, int max) | |
f007fe97 | 155 | { |
87e20041 | 156 | isl_space *space = isl_map_get_space (map); |
157 | int n = isl_space_dim (space, isl_dim_out); | |
a071b80b | 158 | |
87e20041 | 159 | isl_space_free (space); |
160 | return isl_map_add_dims (map, isl_dim_out, max - n); | |
f007fe97 | 161 | } |
162 | ||
87e20041 | 163 | /* Structure used to pass parameters to extend_schedule_1. */ |
0d6b5db2 | 164 | |
87e20041 | 165 | struct extend_schedule_str { |
166 | int max; | |
167 | isl_union_map *umap; | |
168 | }; | |
c6bb733d | 169 | |
87e20041 | 170 | /* Helper function for extend_schedule. */ |
30f4f4a6 | 171 | |
a26dad6a | 172 | static isl_stat |
87e20041 | 173 | extend_schedule_1 (__isl_take isl_map *map, void *user) |
30f4f4a6 | 174 | { |
87e20041 | 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)); | |
a26dad6a | 177 | return isl_stat_ok; |
30f4f4a6 | 178 | } |
179 | ||
87e20041 | 180 | /* Return a relation that has uniform output dimensions. */ |
c6bb733d | 181 | |
7a833a09 | 182 | static __isl_give isl_union_map * |
87e20041 | 183 | extend_schedule (__isl_take isl_union_map *x) |
c6bb733d | 184 | { |
87e20041 | 185 | int max = 0; |
87e20041 | 186 | struct extend_schedule_str str; |
c6bb733d | 187 | |
36620673 | 188 | isl_union_map_foreach_map (x, max_number_of_out_dimensions, (void *) &max); |
87e20041 | 189 | str.max = max; |
190 | str.umap = isl_union_map_empty (isl_union_map_get_space (x)); | |
36620673 | 191 | isl_union_map_foreach_map (x, extend_schedule_1, (void *) &str); |
87e20041 | 192 | isl_union_map_free (x); |
ece4d5b1 | 193 | return isl_union_map_coalesce (str.umap); |
c6bb733d | 194 | } |
195 | ||
87e20041 | 196 | /* Applies SCHEDULE to the in and out dimensions of the dependences |
197 | DEPS and return the resulting relation. */ | |
c6bb733d | 198 | |
87e20041 | 199 | static isl_map * |
200 | apply_schedule_on_deps (__isl_keep isl_union_map *schedule, | |
201 | __isl_keep isl_union_map *deps) | |
c6bb733d | 202 | { |
ece4d5b1 | 203 | isl_union_map *trans = extend_schedule (isl_union_map_copy (schedule)); |
204 | isl_union_map *ux = isl_union_map_copy (deps); | |
87e20041 | 205 | ux = isl_union_map_apply_domain (ux, isl_union_map_copy (trans)); |
206 | ux = isl_union_map_apply_range (ux, trans); | |
ece4d5b1 | 207 | ux = isl_union_map_coalesce (ux); |
208 | ||
209 | if (!isl_union_map_is_empty (ux)) | |
210 | return isl_map_from_union_map (ux); | |
c6bb733d | 211 | |
ece4d5b1 | 212 | isl_union_map_free (ux); |
213 | return NULL; | |
c6bb733d | 214 | } |
215 | ||
87e20041 | 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. */ | |
c6bb733d | 220 | |
86e09dcd | 221 | bool |
87e20041 | 222 | carries_deps (__isl_keep isl_union_map *schedule, |
223 | __isl_keep isl_union_map *deps, | |
224 | int depth) | |
c6bb733d | 225 | { |
87e20041 | 226 | if (isl_union_map_is_empty (deps)) |
227 | return false; | |
c6bb733d | 228 | |
ece4d5b1 | 229 | isl_map *x = apply_schedule_on_deps (schedule, deps); |
86e09dcd | 230 | if (x == NULL) |
231 | return false; | |
87e20041 | 232 | |
ece4d5b1 | 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))); | |
237 | ||
238 | for (int i = 0; i < depth - 1; i++) | |
87e20041 | 239 | lex = isl_map_equate (lex, isl_dim_in, i, isl_dim_out, i); |
240 | ||
241 | /* in + 1 <= out */ | |
bffcae34 | 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); | |
87e20041 | 244 | ineq = isl_constraint_set_constant_si (ineq, -1); |
245 | lex = isl_map_add_constraint (lex, ineq); | |
ece4d5b1 | 246 | lex = isl_map_coalesce (lex); |
87e20041 | 247 | x = isl_map_intersect (x, lex); |
ece4d5b1 | 248 | bool res = !isl_map_is_empty (x); |
87e20041 | 249 | |
250 | isl_map_free (x); | |
251 | return res; | |
c6bb733d | 252 | } |
253 | ||
c1616982 | 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. */ | |
258 | ||
259 | void | |
260 | scop_get_dependences (scop_p scop) | |
261 | { | |
262 | if (scop->dependence) | |
263 | return; | |
264 | ||
9c61da99 | 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); | |
c1616982 | 270 | |
271 | if (dump_file) | |
272 | { | |
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"); | |
279 | ||
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"); | |
288 | ||
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"); | |
297 | } | |
298 | ||
299 | gcc_assert (scop->original_schedule); | |
300 | ||
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); | |
310 | ||
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); | |
317 | ||
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); | |
322 | ||
323 | raw = isl_union_map_coalesce (raw); | |
324 | waw = isl_union_map_coalesce (waw); | |
325 | war = isl_union_map_coalesce (war); | |
326 | ||
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); | |
331 | ||
332 | if (dump_file) | |
333 | { | |
334 | fprintf (dump_file, "data dependences (\n"); | |
335 | print_isl_union_map (dump_file, dependences); | |
336 | fprintf (dump_file, ")\n"); | |
337 | } | |
338 | ||
339 | scop->dependence = dependences; | |
340 | } | |
341 | ||
26bd1f19 | 342 | #endif /* HAVE_isl */ |