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