1 1.1 mrg /* 2 1.1 mrg * Copyright 2021 Sven Verdoolaege 3 1.1 mrg * 4 1.1 mrg * Use of this software is governed by the MIT license 5 1.1 mrg * 6 1.1 mrg * Written by Sven Verdoolaege 7 1.1 mrg */ 8 1.1 mrg 9 1.1 mrg #include <stdio.h> 10 1.1 mrg 11 1.1 mrg #include <isl/ctx.h> 12 1.1 mrg #include <isl/schedule_node.h> 13 1.1 mrg #include <isl/union_set.h> 14 1.1 mrg 15 1.1 mrg #include "isl_hash_private.h" 16 1.1 mrg #include "isl_scheduler_scc.h" 17 1.1 mrg #include "isl_sort.h" 18 1.1 mrg 19 1.1 mrg /* Internal data structure for ordering the SCCs of "graph", 20 1.1 mrg * where each SCC i consists of the single cluster determined 21 1.1 mrg * by c->scc_cluster[i]. The nodes in this cluster all have 22 1.1 mrg * their "scc" field set to i. 23 1.1 mrg * 24 1.1 mrg * "graph" is the original schedule graph. 25 1.1 mrg * "c" contains the clustering information. 26 1.1 mrg * 27 1.1 mrg * "n" is the number of SCCs in the isl_scc_graph, which may be 28 1.1 mrg * a subset of those in "graph". 29 1.1 mrg * "graph_scc" maps the local index of an SCC in this isl_scc_graph 30 1.1 mrg * to the corresponding index in "graph", i.e, the index of c->scc_cluster. 31 1.1 mrg * The entries of "graph_scc" are kept in topological order. 32 1.1 mrg * 33 1.1 mrg * "component" contains the component to which an SCC belongs, 34 1.1 mrg * where the component is represented by the index of the first SCC 35 1.1 mrg * in the component. 36 1.1 mrg * The index of this first SCC is always smaller than or equal 37 1.1 mrg * to the index of the SCC itself. 38 1.1 mrg * This field is initialized by isl_scc_graph_init_component and 39 1.1 mrg * used by detect_components. 40 1.1 mrg * During construction, "component" may also contain the index 41 1.1 mrg * of some other SCC in the component, but then it is necessarily 42 1.1 mrg * smaller than the index of the current SCC and the first SCC 43 1.1 mrg * can be reached by recursively looking up "component". 44 1.1 mrg * "size" contains the number of elements in the components 45 1.1 mrg * indexed by a component sequence number. 46 1.1 mrg * 47 1.1 mrg * "pos" is used locally inside isl_scc_graph_sort_components 48 1.1 mrg * to store the position of the next SCC within a component. 49 1.1 mrg * It is also used inside isl_scc_graph_sub to map 50 1.1 mrg * the position in the original graph to the position in the subgraph. 51 1.1 mrg * 52 1.1 mrg * "sorted" contains the (possibly) reordered local indices, 53 1.1 mrg * sorted per component. Within each component, the original 54 1.1 mrg * topological order is preserved. 55 1.1 mrg * 56 1.1 mrg * "edge_table" contains "n" edge tables, one for each SCC 57 1.1 mrg * in this isl_scc_graph. Each table contains the local indices 58 1.1 mrg * of the SCCs that depend on this SCC. These local indices 59 1.1 mrg * are encoded as pointers to the corresponding entry in "graph_scc". 60 1.1 mrg * The value stored at that location is the global SCC index. 61 1.1 mrg * "reverse_edge_table" contains the inverse edges. 62 1.1 mrg */ 63 1.1 mrg struct isl_scc_graph { 64 1.1 mrg isl_ctx *ctx; 65 1.1 mrg struct isl_sched_graph *graph; 66 1.1 mrg struct isl_clustering *c; 67 1.1 mrg 68 1.1 mrg int n; 69 1.1 mrg int *graph_scc; 70 1.1 mrg int *component; 71 1.1 mrg int *size; 72 1.1 mrg int *pos; 73 1.1 mrg int *sorted; 74 1.1 mrg struct isl_hash_table **edge_table; 75 1.1 mrg struct isl_hash_table **reverse_edge_table; 76 1.1 mrg }; 77 1.1 mrg 78 1.1 mrg /* The source SCC of a collection of edges. 79 1.1 mrg * 80 1.1 mrg * "scc_graph" is the SCC graph containing the edges. 81 1.1 mrg * "src" is the local index of the source SCC. 82 1.1 mrg */ 83 1.1 mrg struct isl_edge_src { 84 1.1 mrg struct isl_scc_graph *scc_graph; 85 1.1 mrg int src; 86 1.1 mrg }; 87 1.1 mrg 88 1.1 mrg /* isl_hash_table_foreach callback for printing an edge 89 1.1 mrg * between "src" and the node identified by "entry". 90 1.1 mrg * The edge is printed in terms of the global SCC indices. 91 1.1 mrg */ 92 1.1 mrg static isl_stat print_edge(void **entry, void *user) 93 1.1 mrg { 94 1.1 mrg int *dst = *entry; 95 1.1 mrg int *src = user; 96 1.1 mrg 97 1.1 mrg fprintf(stderr, "%d -> %d; ", *src, *dst); 98 1.1 mrg 99 1.1 mrg return isl_stat_ok; 100 1.1 mrg } 101 1.1 mrg 102 1.1 mrg /* Print some debugging information about "scc_graph". 103 1.1 mrg * 104 1.1 mrg * In particular, print the nodes and the edges (both forward and backward). 105 1.1 mrg */ 106 1.1 mrg void isl_scc_graph_dump(struct isl_scc_graph *scc_graph) 107 1.1 mrg { 108 1.1 mrg int i; 109 1.1 mrg isl_ctx *ctx; 110 1.1 mrg 111 1.1 mrg if (!scc_graph) 112 1.1 mrg return; 113 1.1 mrg 114 1.1 mrg ctx = scc_graph->ctx; 115 1.1 mrg for (i = 0; i < scc_graph->n; ++i) { 116 1.1 mrg if (i) 117 1.1 mrg fprintf(stderr, ", "); 118 1.1 mrg fprintf(stderr, "%d", scc_graph->graph_scc[i]); 119 1.1 mrg } 120 1.1 mrg fprintf(stderr, "\n"); 121 1.1 mrg for (i = 0; i < scc_graph->n; ++i) { 122 1.1 mrg isl_hash_table_foreach(ctx, scc_graph->edge_table[i], 123 1.1 mrg &print_edge, &scc_graph->graph_scc[i]); 124 1.1 mrg } 125 1.1 mrg fprintf(stderr, "\n"); 126 1.1 mrg for (i = 0; i < scc_graph->n; ++i) { 127 1.1 mrg isl_hash_table_foreach(ctx, scc_graph->reverse_edge_table[i], 128 1.1 mrg &print_edge, &scc_graph->graph_scc[i]); 129 1.1 mrg } 130 1.1 mrg fprintf(stderr, "\n"); 131 1.1 mrg } 132 1.1 mrg 133 1.1 mrg /* Free all memory allocated for "scc_graph" and return NULL. 134 1.1 mrg */ 135 1.1 mrg struct isl_scc_graph *isl_scc_graph_free(struct isl_scc_graph *scc_graph) 136 1.1 mrg { 137 1.1 mrg int i; 138 1.1 mrg isl_ctx *ctx; 139 1.1 mrg 140 1.1 mrg if (!scc_graph) 141 1.1 mrg return NULL; 142 1.1 mrg 143 1.1 mrg ctx = scc_graph->ctx; 144 1.1 mrg if (scc_graph->edge_table) { 145 1.1 mrg for (i = 0; i < scc_graph->n; ++i) 146 1.1 mrg isl_hash_table_free(ctx, scc_graph->edge_table[i]); 147 1.1 mrg } 148 1.1 mrg if (scc_graph->reverse_edge_table) { 149 1.1 mrg for (i = 0; i < scc_graph->n; ++i) 150 1.1 mrg isl_hash_table_free(ctx, 151 1.1 mrg scc_graph->reverse_edge_table[i]); 152 1.1 mrg } 153 1.1 mrg 154 1.1 mrg free(scc_graph->graph_scc); 155 1.1 mrg free(scc_graph->component); 156 1.1 mrg free(scc_graph->size); 157 1.1 mrg free(scc_graph->pos); 158 1.1 mrg free(scc_graph->sorted); 159 1.1 mrg free(scc_graph->edge_table); 160 1.1 mrg free(scc_graph->reverse_edge_table); 161 1.1 mrg isl_ctx_deref(scc_graph->ctx); 162 1.1 mrg free(scc_graph); 163 1.1 mrg return NULL; 164 1.1 mrg } 165 1.1 mrg 166 1.1 mrg /* Return an encoding of the local SCC index "pos" in "scc_graph" 167 1.1 mrg * as a pointer. 168 1.1 mrg * In particular, return a pointer to the corresponding entry 169 1.1 mrg * in scc_graph->graph_scc. 170 1.1 mrg */ 171 1.1 mrg static void *isl_scc_graph_encode_local_index(struct isl_scc_graph *scc_graph, 172 1.1 mrg int pos) 173 1.1 mrg { 174 1.1 mrg return &scc_graph->graph_scc[pos]; 175 1.1 mrg } 176 1.1 mrg 177 1.1 mrg /* Return the local SCC index in "scc_graph" corresponding 178 1.1 mrg * to the "data" encoding in the edge table. 179 1.1 mrg */ 180 1.1 mrg static int isl_scc_graph_local_index(struct isl_scc_graph *scc_graph, int *data) 181 1.1 mrg { 182 1.1 mrg return data - &scc_graph->graph_scc[0]; 183 1.1 mrg } 184 1.1 mrg 185 1.1 mrg /* isl_hash_table_find callback to check whether the given entry 186 1.1 mrg * refers to an SCC encoded as "val". 187 1.1 mrg */ 188 1.1 mrg static isl_bool is_scc_node(const void *entry, const void *val) 189 1.1 mrg { 190 1.1 mrg return entry == val; 191 1.1 mrg } 192 1.1 mrg 193 1.1 mrg /* Return the edge from local SCC index "src" to local SCC index "dst" 194 1.1 mrg * in "edge_table" of "scc_graph", creating one if "reserve" is set. 195 1.1 mrg * If "reserve" is not set, then return isl_hash_table_entry_none 196 1.1 mrg * if there is no such edge. 197 1.1 mrg * 198 1.1 mrg * The destination of the edge is encoded as a pointer 199 1.1 mrg * to the corresponding entry in scc_graph->graph_scc. 200 1.1 mrg */ 201 1.1 mrg struct isl_hash_table_entry *isl_scc_graph_find_edge( 202 1.1 mrg struct isl_scc_graph *scc_graph, struct isl_hash_table **edge_table, 203 1.1 mrg int src, int dst, int reserve) 204 1.1 mrg { 205 1.1 mrg isl_ctx *ctx; 206 1.1 mrg uint32_t hash; 207 1.1 mrg void *val; 208 1.1 mrg 209 1.1 mrg ctx = scc_graph->ctx; 210 1.1 mrg hash = isl_hash_builtin(isl_hash_init(), dst); 211 1.1 mrg val = isl_scc_graph_encode_local_index(scc_graph, dst); 212 1.1 mrg return isl_hash_table_find(ctx, edge_table[src], hash, 213 1.1 mrg &is_scc_node, val, reserve); 214 1.1 mrg } 215 1.1 mrg 216 1.1 mrg /* Remove the edge between the SCCs with local indices "src" and 217 1.1 mrg * "dst" in "scc_graph", if it exits. 218 1.1 mrg * Return isl_bool_true if this is the case. 219 1.1 mrg * 220 1.1 mrg * The edge is only removed from scc_graph->edge_table. 221 1.1 mrg * scc_graph->reverse_edge_table is assumed to be empty 222 1.1 mrg * when this function is called. 223 1.1 mrg */ 224 1.1 mrg static isl_bool isl_scc_graph_remove_edge(struct isl_scc_graph *scc_graph, 225 1.1 mrg int src, int dst) 226 1.1 mrg { 227 1.1 mrg isl_ctx *ctx; 228 1.1 mrg struct isl_hash_table_entry *edge_entry; 229 1.1 mrg 230 1.1 mrg edge_entry = isl_scc_graph_find_edge(scc_graph, scc_graph->edge_table, 231 1.1 mrg src, dst, 0); 232 1.1 mrg if (edge_entry == isl_hash_table_entry_none) 233 1.1 mrg return isl_bool_false; 234 1.1 mrg if (!edge_entry) 235 1.1 mrg return isl_bool_error; 236 1.1 mrg 237 1.1 mrg ctx = scc_graph->ctx; 238 1.1 mrg isl_hash_table_remove(ctx, scc_graph->edge_table[src], edge_entry); 239 1.1 mrg 240 1.1 mrg return isl_bool_true; 241 1.1 mrg } 242 1.1 mrg 243 1.1 mrg /* Internal data structure used by next_nodes. 244 1.1 mrg * 245 1.1 mrg * "scc_graph" is the SCC graph. 246 1.1 mrg * "next" collects the next nodes. 247 1.1 mrg * "n" is the number of next nodes already collected. 248 1.1 mrg */ 249 1.1 mrg struct isl_extract_dst_data { 250 1.1 mrg struct isl_scc_graph *scc_graph; 251 1.1 mrg int *next; 252 1.1 mrg int n; 253 1.1 mrg }; 254 1.1 mrg 255 1.1 mrg /* Given an entry in the edge table, add the corresponding 256 1.1 mrg * target local SCC index to data->next. 257 1.1 mrg */ 258 1.1 mrg static isl_stat extract_dst(void **entry, void *user) 259 1.1 mrg { 260 1.1 mrg int *dst = *entry; 261 1.1 mrg struct isl_extract_dst_data *data = user; 262 1.1 mrg 263 1.1 mrg data->next[data->n++] = isl_scc_graph_local_index(data->scc_graph, dst); 264 1.1 mrg 265 1.1 mrg return isl_stat_ok; 266 1.1 mrg } 267 1.1 mrg 268 1.1 mrg /* isl_sort callback for sorting integers in increasing order. 269 1.1 mrg */ 270 1.1 mrg static int cmp_int(const void *a, const void *b, void *data) 271 1.1 mrg { 272 1.1 mrg const int *i1 = a; 273 1.1 mrg const int *i2 = b; 274 1.1 mrg 275 1.1 mrg return *i1 - *i2; 276 1.1 mrg } 277 1.1 mrg 278 1.1 mrg /* Return the local indices of the SCCs in "scc_graph" 279 1.1 mrg * for which there is an edge from the SCC with local index "i". 280 1.1 mrg * The indices are returned in increasing order, 281 1.1 mrg * i.e., in the original topological order. 282 1.1 mrg */ 283 1.1 mrg static int *next_nodes(struct isl_scc_graph *scc_graph, int i) 284 1.1 mrg { 285 1.1 mrg struct isl_extract_dst_data data; 286 1.1 mrg int n_next; 287 1.1 mrg int *next; 288 1.1 mrg 289 1.1 mrg n_next = scc_graph->edge_table[i]->n; 290 1.1 mrg next = isl_alloc_array(scc_graph->ctx, int, n_next); 291 1.1 mrg if (!next) 292 1.1 mrg return NULL; 293 1.1 mrg data.scc_graph = scc_graph; 294 1.1 mrg data.next = next; 295 1.1 mrg data.n = 0; 296 1.1 mrg if (isl_hash_table_foreach(scc_graph->ctx, scc_graph->edge_table[i], 297 1.1 mrg &extract_dst, &data) < 0) 298 1.1 mrg goto error; 299 1.1 mrg if (isl_sort(next, n_next, sizeof(int), &cmp_int, NULL) < 0) 300 1.1 mrg goto error; 301 1.1 mrg return next; 302 1.1 mrg error: 303 1.1 mrg free(next); 304 1.1 mrg return NULL; 305 1.1 mrg } 306 1.1 mrg 307 1.1 mrg /* Internal data structure for foreach_reachable. 308 1.1 mrg * 309 1.1 mrg * "scc_graph" is the SCC graph being visited. 310 1.1 mrg * "fn" is the function that needs to be called on each reachable node. 311 1.1 mrg * "user" is the user argument to "fn". 312 1.1 mrg */ 313 1.1 mrg struct isl_foreach_reachable_data { 314 1.1 mrg struct isl_scc_graph *scc_graph; 315 1.1 mrg isl_bool (*fn)(int pos, void *user); 316 1.1 mrg void *user; 317 1.1 mrg }; 318 1.1 mrg 319 1.1 mrg static isl_stat foreach_reachable(struct isl_foreach_reachable_data *data, 320 1.1 mrg int pos); 321 1.1 mrg 322 1.1 mrg /* isl_hash_table_foreach callback for calling data->fn on each SCC 323 1.1 mrg * reachable from the SCC encoded in "entry", 324 1.1 mrg * continuing from an SCC as long as data->fn returns isl_bool_true. 325 1.1 mrg */ 326 1.1 mrg static isl_stat recurse_foreach_reachable(void **entry, void *user) 327 1.1 mrg { 328 1.1 mrg struct isl_foreach_reachable_data *data = user; 329 1.1 mrg int pos; 330 1.1 mrg isl_bool more; 331 1.1 mrg 332 1.1 mrg pos = isl_scc_graph_local_index(data->scc_graph, *entry); 333 1.1 mrg more = data->fn(pos, data->user); 334 1.1 mrg if (more < 0) 335 1.1 mrg return isl_stat_error; 336 1.1 mrg if (!more) 337 1.1 mrg return isl_stat_ok; 338 1.1 mrg 339 1.1 mrg return foreach_reachable(data, pos); 340 1.1 mrg } 341 1.1 mrg 342 1.1 mrg /* Call data->fn on each SCC reachable from the SCC with local index "pos", 343 1.1 mrg * continuing from an SCC as long as data->fn returns isl_bool_true. 344 1.1 mrg * 345 1.1 mrg * Handle chains directly and recurse when an SCC has more than one 346 1.1 mrg * outgoing edge. 347 1.1 mrg */ 348 1.1 mrg static isl_stat foreach_reachable(struct isl_foreach_reachable_data *data, 349 1.1 mrg int pos) 350 1.1 mrg { 351 1.1 mrg isl_ctx *ctx; 352 1.1 mrg struct isl_hash_table **edge_table = data->scc_graph->edge_table; 353 1.1 mrg 354 1.1 mrg while (edge_table[pos]->n == 1) { 355 1.1 mrg struct isl_hash_table_entry *entry; 356 1.1 mrg isl_bool more; 357 1.1 mrg 358 1.1 mrg entry = isl_hash_table_first(edge_table[pos]); 359 1.1 mrg pos = isl_scc_graph_local_index(data->scc_graph, entry->data); 360 1.1 mrg more = data->fn(pos, data->user); 361 1.1 mrg if (more < 0) 362 1.1 mrg return isl_stat_error; 363 1.1 mrg if (!more) 364 1.1 mrg return isl_stat_ok; 365 1.1 mrg } 366 1.1 mrg 367 1.1 mrg if (edge_table[pos]->n == 0) 368 1.1 mrg return isl_stat_ok; 369 1.1 mrg 370 1.1 mrg ctx = data->scc_graph->ctx; 371 1.1 mrg return isl_hash_table_foreach(ctx, edge_table[pos], 372 1.1 mrg &recurse_foreach_reachable, data); 373 1.1 mrg } 374 1.1 mrg 375 1.1 mrg /* If there is an edge from data->src to "pos", then remove it. 376 1.1 mrg * Return isl_bool_true if descendants of "pos" still need to be considered. 377 1.1 mrg * 378 1.1 mrg * Descendants only need to be considered if no edge is removed. 379 1.1 mrg */ 380 1.1 mrg static isl_bool elim_or_next(int pos, void *user) 381 1.1 mrg { 382 1.1 mrg struct isl_edge_src *data = user; 383 1.1 mrg struct isl_scc_graph *scc_graph = data->scc_graph; 384 1.1 mrg isl_bool removed; 385 1.1 mrg 386 1.1 mrg removed = isl_scc_graph_remove_edge(scc_graph, data->src, pos); 387 1.1 mrg return isl_bool_not(removed); 388 1.1 mrg } 389 1.1 mrg 390 1.1 mrg /* Remove transitive edges from "scc_graph". 391 1.1 mrg * 392 1.1 mrg * Consider the SCC nodes "i" in reverse topological order. 393 1.1 mrg * If there is more than one edge emanating from a node, 394 1.1 mrg * then eliminate the edges to those nodes that can also be reached 395 1.1 mrg * through an edge to a node with a smaller index. 396 1.1 mrg * In particular, consider all but the last next nodes "next[j]" 397 1.1 mrg * in reverse topological order. If any node "k" can be reached 398 1.1 mrg * from such a node for which there is also an edge from "i" 399 1.1 mrg * then this edge can be removed because this node can also 400 1.1 mrg * be reached from "i" through the edge to "next[j]". 401 1.1 mrg * If such an edge is removed, then any further descendant of "k" 402 1.1 mrg * does not need to be considered since these were already considered 403 1.1 mrg * for a previous "next[j]" equal to "k", or "k" is the last next node, 404 1.1 mrg * in which case there is no further node with an edge from "i". 405 1.1 mrg */ 406 1.1 mrg static struct isl_scc_graph *isl_scc_graph_reduce( 407 1.1 mrg struct isl_scc_graph *scc_graph) 408 1.1 mrg { 409 1.1 mrg struct isl_edge_src elim_data; 410 1.1 mrg struct isl_foreach_reachable_data data = { 411 1.1 mrg .scc_graph = scc_graph, 412 1.1 mrg .fn = &elim_or_next, 413 1.1 mrg .user = &elim_data, 414 1.1 mrg }; 415 1.1 mrg int i, j; 416 1.1 mrg 417 1.1 mrg elim_data.scc_graph = scc_graph; 418 1.1 mrg for (i = scc_graph->n - 3; i >= 0; --i) { 419 1.1 mrg int *next; 420 1.1 mrg int n_next; 421 1.1 mrg 422 1.1 mrg n_next = scc_graph->edge_table[i]->n; 423 1.1 mrg if (n_next <= 1) 424 1.1 mrg continue; 425 1.1 mrg next = next_nodes(scc_graph, i); 426 1.1 mrg if (!next) 427 1.1 mrg return isl_scc_graph_free(scc_graph); 428 1.1 mrg 429 1.1 mrg elim_data.src = i; 430 1.1 mrg for (j = n_next - 2; j >= 0; --j) 431 1.1 mrg if (foreach_reachable(&data, next[j]) < 0) 432 1.1 mrg break; 433 1.1 mrg free(next); 434 1.1 mrg if (j >= 0) 435 1.1 mrg return isl_scc_graph_free(scc_graph); 436 1.1 mrg } 437 1.1 mrg 438 1.1 mrg return scc_graph; 439 1.1 mrg } 440 1.1 mrg 441 1.1 mrg /* Add an edge to "edge_table" between the SCCs with local indices "src" and 442 1.1 mrg * "dst" in "scc_graph". 443 1.1 mrg * 444 1.1 mrg * If the edge already appeared in the table, then it is simply overwritten 445 1.1 mrg * with the same information. 446 1.1 mrg */ 447 1.1 mrg static isl_stat isl_scc_graph_add_edge(struct isl_scc_graph *scc_graph, 448 1.1 mrg struct isl_hash_table **edge_table, int src, int dst) 449 1.1 mrg { 450 1.1 mrg struct isl_hash_table_entry *edge_entry; 451 1.1 mrg 452 1.1 mrg edge_entry = 453 1.1 mrg isl_scc_graph_find_edge(scc_graph, edge_table, src, dst, 1); 454 1.1 mrg if (!edge_entry) 455 1.1 mrg return isl_stat_error; 456 1.1 mrg edge_entry->data = &scc_graph->graph_scc[dst]; 457 1.1 mrg 458 1.1 mrg return isl_stat_ok; 459 1.1 mrg } 460 1.1 mrg 461 1.1 mrg /* Add an edge from "dst" to data->src 462 1.1 mrg * to data->scc_graph->reverse_edge_table. 463 1.1 mrg */ 464 1.1 mrg static isl_stat add_reverse(void **entry, void *user) 465 1.1 mrg { 466 1.1 mrg struct isl_edge_src *data = user; 467 1.1 mrg int dst; 468 1.1 mrg 469 1.1 mrg dst = isl_scc_graph_local_index(data->scc_graph, *entry); 470 1.1 mrg return isl_scc_graph_add_edge(data->scc_graph, 471 1.1 mrg data->scc_graph->reverse_edge_table, dst, data->src); 472 1.1 mrg } 473 1.1 mrg 474 1.1 mrg /* Add an (inverse) edge to scc_graph->reverse_edge_table 475 1.1 mrg * for each edge in scc_graph->edge_table. 476 1.1 mrg */ 477 1.1 mrg static struct isl_scc_graph *isl_scc_graph_add_reverse_edges( 478 1.1 mrg struct isl_scc_graph *scc_graph) 479 1.1 mrg { 480 1.1 mrg struct isl_edge_src data; 481 1.1 mrg isl_ctx *ctx; 482 1.1 mrg 483 1.1 mrg if (!scc_graph) 484 1.1 mrg return NULL; 485 1.1 mrg 486 1.1 mrg ctx = scc_graph->ctx; 487 1.1 mrg data.scc_graph = scc_graph; 488 1.1 mrg for (data.src = 0; data.src < scc_graph->n; ++data.src) { 489 1.1 mrg if (isl_hash_table_foreach(ctx, scc_graph->edge_table[data.src], 490 1.1 mrg &add_reverse, &data) < 0) 491 1.1 mrg return isl_scc_graph_free(scc_graph); 492 1.1 mrg } 493 1.1 mrg return scc_graph; 494 1.1 mrg } 495 1.1 mrg 496 1.1 mrg /* Given an edge in the schedule graph, add an edge between 497 1.1 mrg * the corresponding SCCs in "scc_graph", if they are distinct. 498 1.1 mrg * 499 1.1 mrg * This function is used to create edges in the original isl_scc_graph. 500 1.1 mrg * where the local SCC indices are equal to the corresponding global 501 1.1 mrg * indices. 502 1.1 mrg */ 503 1.1 mrg static isl_stat add_scc_edge(void **entry, void *user) 504 1.1 mrg { 505 1.1 mrg struct isl_sched_edge *edge = *entry; 506 1.1 mrg struct isl_scc_graph *scc_graph = user; 507 1.1 mrg int src = edge->src->scc; 508 1.1 mrg int dst = edge->dst->scc; 509 1.1 mrg 510 1.1 mrg if (src == dst) 511 1.1 mrg return isl_stat_ok; 512 1.1 mrg 513 1.1 mrg return isl_scc_graph_add_edge(scc_graph, scc_graph->edge_table, 514 1.1 mrg src, dst); 515 1.1 mrg } 516 1.1 mrg 517 1.1 mrg /* Allocate an isl_scc_graph for ordering "n" SCCs of "graph" 518 1.1 mrg * with clustering information in "c". 519 1.1 mrg * 520 1.1 mrg * The caller still needs to fill in the edges. 521 1.1 mrg */ 522 1.1 mrg static struct isl_scc_graph *isl_scc_graph_alloc(isl_ctx *ctx, int n, 523 1.1 mrg struct isl_sched_graph *graph, struct isl_clustering *c) 524 1.1 mrg { 525 1.1 mrg int i; 526 1.1 mrg struct isl_scc_graph *scc_graph; 527 1.1 mrg 528 1.1 mrg scc_graph = isl_alloc_type(ctx, struct isl_scc_graph); 529 1.1 mrg if (!scc_graph) 530 1.1 mrg return NULL; 531 1.1 mrg 532 1.1 mrg scc_graph->ctx = ctx; 533 1.1 mrg isl_ctx_ref(ctx); 534 1.1 mrg scc_graph->graph = graph; 535 1.1 mrg scc_graph->c = c; 536 1.1 mrg 537 1.1 mrg scc_graph->n = n; 538 1.1 mrg scc_graph->graph_scc = isl_alloc_array(ctx, int, n); 539 1.1 mrg scc_graph->component = isl_alloc_array(ctx, int, n); 540 1.1 mrg scc_graph->size = isl_alloc_array(ctx, int, n); 541 1.1 mrg scc_graph->pos = isl_alloc_array(ctx, int, n); 542 1.1 mrg scc_graph->sorted = isl_alloc_array(ctx, int, n); 543 1.1 mrg scc_graph->edge_table = 544 1.1 mrg isl_calloc_array(ctx, struct isl_hash_table *, n); 545 1.1 mrg scc_graph->reverse_edge_table = 546 1.1 mrg isl_calloc_array(ctx, struct isl_hash_table *, n); 547 1.1 mrg if (!scc_graph->graph_scc || !scc_graph->component || 548 1.1 mrg !scc_graph->size || !scc_graph->pos || !scc_graph->sorted || 549 1.1 mrg !scc_graph->edge_table || !scc_graph->reverse_edge_table) 550 1.1 mrg return isl_scc_graph_free(scc_graph); 551 1.1 mrg 552 1.1 mrg for (i = 0; i < n; ++i) { 553 1.1 mrg scc_graph->edge_table[i] = isl_hash_table_alloc(ctx, 2); 554 1.1 mrg scc_graph->reverse_edge_table[i] = isl_hash_table_alloc(ctx, 2); 555 1.1 mrg if (!scc_graph->edge_table[i] || 556 1.1 mrg !scc_graph->reverse_edge_table[i]) 557 1.1 mrg return isl_scc_graph_free(scc_graph); 558 1.1 mrg } 559 1.1 mrg 560 1.1 mrg return scc_graph; 561 1.1 mrg } 562 1.1 mrg 563 1.1 mrg /* Construct an isl_scc_graph for ordering the SCCs of "graph", 564 1.1 mrg * where each SCC i consists of the single cluster determined 565 1.1 mrg * by c->scc_cluster[i]. The nodes in this cluster all have 566 1.1 mrg * their "scc" field set to i. 567 1.1 mrg * 568 1.1 mrg * The initial isl_scc_graph has as many SCCs as "graph" and 569 1.1 mrg * their local indices are the same as their indices in "graph". 570 1.1 mrg * 571 1.1 mrg * Add edges between different SCCs for each (conditional) validity edge 572 1.1 mrg * between nodes in those SCCs, remove transitive edges and 573 1.1 mrg * construct the inverse edges from the remaining forward edges. 574 1.1 mrg */ 575 1.1 mrg struct isl_scc_graph *isl_scc_graph_from_sched_graph(isl_ctx *ctx, 576 1.1 mrg struct isl_sched_graph *graph, struct isl_clustering *c) 577 1.1 mrg { 578 1.1 mrg int i; 579 1.1 mrg struct isl_scc_graph *scc_graph; 580 1.1 mrg 581 1.1 mrg scc_graph = isl_scc_graph_alloc(ctx, graph->scc, graph, c); 582 1.1 mrg if (!scc_graph) 583 1.1 mrg return NULL; 584 1.1 mrg 585 1.1 mrg for (i = 0; i < graph->scc; ++i) 586 1.1 mrg scc_graph->graph_scc[i] = i; 587 1.1 mrg 588 1.1 mrg if (isl_hash_table_foreach(ctx, graph->edge_table[isl_edge_validity], 589 1.1 mrg &add_scc_edge, scc_graph) < 0) 590 1.1 mrg return isl_scc_graph_free(scc_graph); 591 1.1 mrg if (isl_hash_table_foreach(ctx, 592 1.1 mrg graph->edge_table[isl_edge_conditional_validity], 593 1.1 mrg &add_scc_edge, scc_graph) < 0) 594 1.1 mrg return isl_scc_graph_free(scc_graph); 595 1.1 mrg 596 1.1 mrg scc_graph = isl_scc_graph_reduce(scc_graph); 597 1.1 mrg scc_graph = isl_scc_graph_add_reverse_edges(scc_graph); 598 1.1 mrg 599 1.1 mrg return scc_graph; 600 1.1 mrg } 601 1.1 mrg 602 1.1 mrg /* Internal data structure for copy_edge. 603 1.1 mrg * 604 1.1 mrg * "scc_graph" is the original graph. 605 1.1 mrg * "sub" is the subgraph to which edges are being copied. 606 1.1 mrg * "src" is the local index in "scc_graph" of the source of the edges 607 1.1 mrg * currently being copied. 608 1.1 mrg */ 609 1.1 mrg struct isl_copy_edge_data { 610 1.1 mrg struct isl_scc_graph *scc_graph; 611 1.1 mrg struct isl_scc_graph *sub; 612 1.1 mrg int src; 613 1.1 mrg }; 614 1.1 mrg 615 1.1 mrg /* isl_hash_table_foreach callback for copying the edge 616 1.1 mrg * from data->src to the node identified by "entry" 617 1.1 mrg * to data->sub, provided the two nodes belong to the same component. 618 1.1 mrg * Note that by construction, there are no edges between different components 619 1.1 mrg * in the region handled by detect_components, but there may 620 1.1 mrg * be edges to nodes outside this region. 621 1.1 mrg * The components therefore need to be initialized for all nodes 622 1.1 mrg * in isl_scc_graph_init_component. 623 1.1 mrg */ 624 1.1 mrg static isl_stat copy_edge(void **entry, void *user) 625 1.1 mrg { 626 1.1 mrg struct isl_copy_edge_data *data = user; 627 1.1 mrg struct isl_scc_graph *scc_graph = data->scc_graph; 628 1.1 mrg struct isl_scc_graph *sub = data->sub; 629 1.1 mrg int dst, sub_dst, sub_src; 630 1.1 mrg 631 1.1 mrg dst = isl_scc_graph_local_index(data->scc_graph, *entry); 632 1.1 mrg if (scc_graph->component[dst] != scc_graph->component[data->src]) 633 1.1 mrg return isl_stat_ok; 634 1.1 mrg 635 1.1 mrg sub_src = scc_graph->pos[data->src]; 636 1.1 mrg sub_dst = scc_graph->pos[dst]; 637 1.1 mrg 638 1.1 mrg return isl_scc_graph_add_edge(sub, sub->edge_table, sub_src, sub_dst); 639 1.1 mrg } 640 1.1 mrg 641 1.1 mrg /* Construct a subgraph of "scc_graph" for the components 642 1.1 mrg * consisting of the "n" SCCs with local indices in "pos". 643 1.1 mrg * These SCCs have the same value in scc_graph->component and 644 1.1 mrg * this value is different from that of any other SCC. 645 1.1 mrg * 646 1.1 mrg * The forward edges with source and destination in the component 647 1.1 mrg * are copied from "scc_graph". 648 1.1 mrg * The local index in the subgraph corresponding to a local index 649 1.1 mrg * in "scc_graph" is stored in scc_graph->pos for use by copy_edge(). 650 1.1 mrg * The inverse edges are constructed directly from the forward edges. 651 1.1 mrg */ 652 1.1 mrg static struct isl_scc_graph *isl_scc_graph_sub(struct isl_scc_graph *scc_graph, 653 1.1 mrg int *pos, int n) 654 1.1 mrg { 655 1.1 mrg int i; 656 1.1 mrg isl_ctx *ctx; 657 1.1 mrg struct isl_scc_graph *sub; 658 1.1 mrg struct isl_copy_edge_data data; 659 1.1 mrg 660 1.1 mrg if (!scc_graph) 661 1.1 mrg return NULL; 662 1.1 mrg 663 1.1 mrg ctx = scc_graph->ctx; 664 1.1 mrg sub = isl_scc_graph_alloc(ctx, n, scc_graph->graph, scc_graph->c); 665 1.1 mrg if (!sub) 666 1.1 mrg return sub; 667 1.1 mrg 668 1.1 mrg for (i = 0; i < n; ++i) 669 1.1 mrg sub->graph_scc[i] = scc_graph->graph_scc[pos[i]]; 670 1.1 mrg 671 1.1 mrg for (i = 0; i < n; ++i) 672 1.1 mrg scc_graph->pos[pos[i]] = i; 673 1.1 mrg 674 1.1 mrg data.scc_graph = scc_graph; 675 1.1 mrg data.sub = sub; 676 1.1 mrg for (i = 0; i < n; ++i) { 677 1.1 mrg data.src = pos[i]; 678 1.1 mrg if (isl_hash_table_foreach(ctx, scc_graph->edge_table[pos[i]], 679 1.1 mrg ©_edge, &data) < 0) 680 1.1 mrg return isl_scc_graph_free(sub); 681 1.1 mrg } 682 1.1 mrg 683 1.1 mrg sub = isl_scc_graph_add_reverse_edges(sub); 684 1.1 mrg 685 1.1 mrg return sub; 686 1.1 mrg } 687 1.1 mrg 688 1.1 mrg /* Return a union of universe domains corresponding to the nodes 689 1.1 mrg * in the SCC with local index "pos". 690 1.1 mrg */ 691 1.1 mrg static __isl_give isl_union_set *isl_scc_graph_extract_local_scc( 692 1.1 mrg struct isl_scc_graph *scc_graph, int pos) 693 1.1 mrg { 694 1.1 mrg return isl_sched_graph_extract_scc(scc_graph->ctx, scc_graph->graph, 695 1.1 mrg scc_graph->graph_scc[pos]); 696 1.1 mrg } 697 1.1 mrg 698 1.1 mrg /* Construct a filter corresponding to a sequence of "n" local SCC indices 699 1.1 mrg * determined by successive calls to "el", 700 1.1 mrg * add this filter to "list" and 701 1.1 mrg * return the result. 702 1.1 mrg */ 703 1.1 mrg static __isl_give isl_union_set_list *add_scc_seq( 704 1.1 mrg struct isl_scc_graph *scc_graph, 705 1.1 mrg int (*el)(int i, void *user), void *user, int n, 706 1.1 mrg __isl_take isl_union_set_list *list) 707 1.1 mrg { 708 1.1 mrg int i; 709 1.1 mrg isl_union_set *dom; 710 1.1 mrg 711 1.1 mrg dom = isl_union_set_empty_ctx(scc_graph->ctx); 712 1.1 mrg for (i = 0; i < n; ++i) 713 1.1 mrg dom = isl_union_set_union(dom, 714 1.1 mrg isl_scc_graph_extract_local_scc(scc_graph, el(i, user))); 715 1.1 mrg 716 1.1 mrg return isl_union_set_list_add(list, dom); 717 1.1 mrg } 718 1.1 mrg 719 1.1 mrg /* add_scc_seq callback that, on successive calls, returns a sequence 720 1.1 mrg * of local SCC indices starting at "first". 721 1.1 mrg */ 722 1.1 mrg static int offset(int i, void *user) 723 1.1 mrg { 724 1.1 mrg int *first = user; 725 1.1 mrg 726 1.1 mrg return *first + i; 727 1.1 mrg } 728 1.1 mrg 729 1.1 mrg /* Construct a filter corresponding to a sequence of "n" local SCC indices 730 1.1 mrg * starting at "first", add this filter to "list" and return the result. 731 1.1 mrg */ 732 1.1 mrg static __isl_give isl_union_set_list *isl_scc_graph_add_scc_seq( 733 1.1 mrg struct isl_scc_graph *scc_graph, int first, int n, 734 1.1 mrg __isl_take isl_union_set_list *list) 735 1.1 mrg { 736 1.1 mrg return add_scc_seq(scc_graph, &offset, &first, n, list); 737 1.1 mrg } 738 1.1 mrg 739 1.1 mrg /* add_scc_seq callback that, on successive calls, returns the sequence 740 1.1 mrg * of local SCC indices in "seq". 741 1.1 mrg */ 742 1.1 mrg static int at(int i, void *user) 743 1.1 mrg { 744 1.1 mrg int *seq = user; 745 1.1 mrg 746 1.1 mrg return seq[i]; 747 1.1 mrg } 748 1.1 mrg 749 1.1 mrg /* Construct a filter corresponding to the sequence of "n" local SCC indices 750 1.1 mrg * stored in "seq", add this filter to "list" and return the result. 751 1.1 mrg */ 752 1.1 mrg static __isl_give isl_union_set_list *isl_scc_graph_add_scc_indirect_seq( 753 1.1 mrg struct isl_scc_graph *scc_graph, int *seq, int n, 754 1.1 mrg __isl_take isl_union_set_list *list) 755 1.1 mrg { 756 1.1 mrg return add_scc_seq(scc_graph, &at, seq, n, list); 757 1.1 mrg } 758 1.1 mrg 759 1.1 mrg /* Extract out a list of filters for a sequence node that splits 760 1.1 mrg * the graph along the SCC with local index "pos". 761 1.1 mrg * 762 1.1 mrg * The list contains (at most) three elements, 763 1.1 mrg * the SCCs before "pos" (in the topological order), 764 1.1 mrg * "pos" itself, and 765 1.1 mrg * the SCCs after "pos". 766 1.1 mrg */ 767 1.1 mrg static __isl_give isl_union_set_list *extract_split_scc( 768 1.1 mrg struct isl_scc_graph *scc_graph, int pos) 769 1.1 mrg { 770 1.1 mrg isl_union_set *dom; 771 1.1 mrg isl_union_set_list *filters; 772 1.1 mrg 773 1.1 mrg filters = isl_union_set_list_alloc(scc_graph->ctx, 3); 774 1.1 mrg if (pos > 0) 775 1.1 mrg filters = isl_scc_graph_add_scc_seq(scc_graph, 0, pos, filters); 776 1.1 mrg dom = isl_scc_graph_extract_local_scc(scc_graph, pos); 777 1.1 mrg filters = isl_union_set_list_add(filters, dom); 778 1.1 mrg if (pos + 1 < scc_graph->n) 779 1.1 mrg filters = isl_scc_graph_add_scc_seq(scc_graph, 780 1.1 mrg pos + 1, scc_graph->n - (pos + 1), filters); 781 1.1 mrg return filters; 782 1.1 mrg } 783 1.1 mrg 784 1.1 mrg /* Call isl_schedule_node_compute_finish_band on the cluster 785 1.1 mrg * corresponding to the SCC with local index "pos". 786 1.1 mrg * 787 1.1 mrg * First obtain the corresponding SCC index in scc_graph->graph and 788 1.1 mrg * then obtain the corresponding cluster. 789 1.1 mrg */ 790 1.1 mrg static __isl_give isl_schedule_node *isl_scc_graph_finish_band( 791 1.1 mrg struct isl_scc_graph *scc_graph, __isl_take isl_schedule_node *node, 792 1.1 mrg int pos) 793 1.1 mrg { 794 1.1 mrg struct isl_clustering *c = scc_graph->c; 795 1.1 mrg int cluster; 796 1.1 mrg 797 1.1 mrg cluster = c->scc_cluster[scc_graph->graph_scc[pos]]; 798 1.1 mrg return isl_schedule_node_compute_finish_band(node, 799 1.1 mrg &c->cluster[cluster], 0); 800 1.1 mrg } 801 1.1 mrg 802 1.1 mrg /* Given that the SCCs in "scc_graph" form a chain, 803 1.1 mrg * call isl_schedule_node_compute_finish_band on each of the clusters 804 1.1 mrg * in scc_graph->c and update "node" to arrange for them to be executed 805 1.1 mrg * in topological order. 806 1.1 mrg */ 807 1.1 mrg static __isl_give isl_schedule_node *isl_scc_graph_chain( 808 1.1 mrg struct isl_scc_graph *scc_graph, __isl_take isl_schedule_node *node) 809 1.1 mrg { 810 1.1 mrg int i; 811 1.1 mrg isl_union_set *dom; 812 1.1 mrg isl_union_set_list *filters; 813 1.1 mrg 814 1.1 mrg filters = isl_union_set_list_alloc(scc_graph->ctx, scc_graph->n); 815 1.1 mrg for (i = 0; i < scc_graph->n; ++i) { 816 1.1 mrg dom = isl_scc_graph_extract_local_scc(scc_graph, i); 817 1.1 mrg filters = isl_union_set_list_add(filters, dom); 818 1.1 mrg } 819 1.1 mrg 820 1.1 mrg node = isl_schedule_node_insert_sequence(node, filters); 821 1.1 mrg 822 1.1 mrg for (i = 0; i < scc_graph->n; ++i) { 823 1.1 mrg node = isl_schedule_node_grandchild(node, i, 0); 824 1.1 mrg node = isl_scc_graph_finish_band(scc_graph, node, i); 825 1.1 mrg node = isl_schedule_node_grandparent(node); 826 1.1 mrg } 827 1.1 mrg 828 1.1 mrg return node; 829 1.1 mrg } 830 1.1 mrg 831 1.1 mrg /* Recursively call isl_scc_graph_decompose on a subgraph 832 1.1 mrg * consisting of the "n" SCCs with local indices in "pos". 833 1.1 mrg * 834 1.1 mrg * If this component contains only a single SCC, 835 1.1 mrg * then there is no need for a further recursion and 836 1.1 mrg * isl_schedule_node_compute_finish_band can be called directly. 837 1.1 mrg */ 838 1.1 mrg static __isl_give isl_schedule_node *recurse(struct isl_scc_graph *scc_graph, 839 1.1 mrg int *pos, int n, __isl_take isl_schedule_node *node) 840 1.1 mrg { 841 1.1 mrg struct isl_scc_graph *sub; 842 1.1 mrg 843 1.1 mrg if (n == 1) 844 1.1 mrg return isl_scc_graph_finish_band(scc_graph, node, pos[0]); 845 1.1 mrg 846 1.1 mrg sub = isl_scc_graph_sub(scc_graph, pos, n); 847 1.1 mrg if (!sub) 848 1.1 mrg return isl_schedule_node_free(node); 849 1.1 mrg node = isl_scc_graph_decompose(sub, node); 850 1.1 mrg isl_scc_graph_free(sub); 851 1.1 mrg 852 1.1 mrg return node; 853 1.1 mrg } 854 1.1 mrg 855 1.1 mrg /* Initialize the component field of "scc_graph". 856 1.1 mrg * Initially, each SCC belongs to its own single-element component. 857 1.1 mrg * 858 1.1 mrg * Note that the SCC on which isl_scc_graph_decompose performs a split 859 1.1 mrg * also needs to be assigned a component because the components 860 1.1 mrg * are also used in copy_edge to extract a subgraph. 861 1.1 mrg */ 862 1.1 mrg static void isl_scc_graph_init_component(struct isl_scc_graph *scc_graph) 863 1.1 mrg { 864 1.1 mrg int i; 865 1.1 mrg 866 1.1 mrg for (i = 0; i < scc_graph->n; ++i) 867 1.1 mrg scc_graph->component[i] = i; 868 1.1 mrg } 869 1.1 mrg 870 1.1 mrg /* Set the component of "a" to be the same as that of "b" and 871 1.1 mrg * return the original component of "a". 872 1.1 mrg */ 873 1.1 mrg static int assign(int *component, int a, int b) 874 1.1 mrg { 875 1.1 mrg int t; 876 1.1 mrg 877 1.1 mrg t = component[a]; 878 1.1 mrg component[a] = component[b]; 879 1.1 mrg return t; 880 1.1 mrg } 881 1.1 mrg 882 1.1 mrg /* Merge the components containing the SCCs with indices "a" and "b". 883 1.1 mrg * 884 1.1 mrg * If "a" and "b" already belong to the same component, then nothing 885 1.1 mrg * needs to be done. 886 1.1 mrg * Otherwise, make sure both point to the same component. 887 1.1 mrg * In particular, use the SCC in the component entries with the smallest index. 888 1.1 mrg * If the other SCC was the first of its component then the entire 889 1.1 mrg * component now (eventually) points to the other component. 890 1.1 mrg * Otherwise, the earlier parts of the component still need 891 1.1 mrg * to be merged with the other component. 892 1.1 mrg * 893 1.1 mrg * At each stage, either a or b is replaced by either a or b itself, 894 1.1 mrg * in which case the merging terminates because a and b already 895 1.1 mrg * point to the same component, or an SCC index with a smaller value. 896 1.1 mrg * This ensures the merging terminates at some point. 897 1.1 mrg */ 898 1.1 mrg static void isl_scc_graph_merge_src_dst(struct isl_scc_graph *scc_graph, 899 1.1 mrg int a, int b) 900 1.1 mrg { 901 1.1 mrg int *component = scc_graph->component; 902 1.1 mrg 903 1.1 mrg while (component[a] != component[b]) { 904 1.1 mrg if (component[a] < component[b]) 905 1.1 mrg b = assign(component, b, a); 906 1.1 mrg else 907 1.1 mrg a = assign(component, a, b); 908 1.1 mrg } 909 1.1 mrg } 910 1.1 mrg 911 1.1 mrg /* Internal data structure for isl_scc_graph_merge_components. 912 1.1 mrg * 913 1.1 mrg * "scc_graph" is the SCC graph containing the edges. 914 1.1 mrg * "src" is the local index of the source SCC. 915 1.1 mrg * "end" is the local index beyond the sequence being considered. 916 1.1 mrg */ 917 1.1 mrg struct isl_merge_src_dst_data { 918 1.1 mrg struct isl_scc_graph *scc_graph; 919 1.1 mrg int src; 920 1.1 mrg int end; 921 1.1 mrg }; 922 1.1 mrg 923 1.1 mrg /* isl_hash_table_foreach callback for merging the components 924 1.1 mrg * of data->src and the node represented by "entry", provided 925 1.1 mrg * it is within the sequence being considered. 926 1.1 mrg */ 927 1.1 mrg static isl_stat merge_src_dst(void **entry, void *user) 928 1.1 mrg { 929 1.1 mrg struct isl_merge_src_dst_data *data = user; 930 1.1 mrg int dst; 931 1.1 mrg 932 1.1 mrg dst = isl_scc_graph_local_index(data->scc_graph, *entry); 933 1.1 mrg if (dst >= data->end) 934 1.1 mrg return isl_stat_ok; 935 1.1 mrg 936 1.1 mrg isl_scc_graph_merge_src_dst(data->scc_graph, data->src, dst); 937 1.1 mrg 938 1.1 mrg return isl_stat_ok; 939 1.1 mrg } 940 1.1 mrg 941 1.1 mrg /* Merge components of the "n" SCCs starting at "first" that are connected 942 1.1 mrg * by an edge. 943 1.1 mrg */ 944 1.1 mrg static isl_stat isl_scc_graph_merge_components(struct isl_scc_graph *scc_graph, 945 1.1 mrg int first, int n) 946 1.1 mrg { 947 1.1 mrg int i; 948 1.1 mrg struct isl_merge_src_dst_data data; 949 1.1 mrg isl_ctx *ctx = scc_graph->ctx; 950 1.1 mrg 951 1.1 mrg data.scc_graph = scc_graph; 952 1.1 mrg data.end = first + n; 953 1.1 mrg for (i = 0; i < n; ++i) { 954 1.1 mrg data.src = first + i; 955 1.1 mrg if (isl_hash_table_foreach(ctx, scc_graph->edge_table[data.src], 956 1.1 mrg &merge_src_dst, &data) < 0) 957 1.1 mrg return isl_stat_error; 958 1.1 mrg } 959 1.1 mrg 960 1.1 mrg return isl_stat_ok; 961 1.1 mrg } 962 1.1 mrg 963 1.1 mrg /* Sort the "n" local SCC indices starting at "first" according 964 1.1 mrg * to component, store them in scc_graph->sorted and 965 1.1 mrg * return the number of components. 966 1.1 mrg * The sizes of the components are stored in scc_graph->size. 967 1.1 mrg * Only positions starting at "first" are used within 968 1.1 mrg * scc_graph->sorted and scc_graph->size. 969 1.1 mrg * 970 1.1 mrg * The representation of the components is first normalized. 971 1.1 mrg * The normalization ensures that each SCC in a component 972 1.1 mrg * points to the first SCC in the component, whereas 973 1.1 mrg * before this function is called, some SCCs may only point 974 1.1 mrg * to some other SCC in the component with a smaller index. 975 1.1 mrg * 976 1.1 mrg * Internally, the sizes of the components are first stored 977 1.1 mrg * at indices corresponding to the first SCC in the component. 978 1.1 mrg * They are subsequently moved into consecutive positions 979 1.1 mrg * while reordering the local indices. 980 1.1 mrg * This reordering is performed by first determining the position 981 1.1 mrg * of the first SCC in each component and 982 1.1 mrg * then putting the "n" local indices in the right position 983 1.1 mrg * according to the component, preserving the topological order 984 1.1 mrg * within each component. 985 1.1 mrg */ 986 1.1 mrg static int isl_scc_graph_sort_components(struct isl_scc_graph *scc_graph, 987 1.1 mrg int first, int n) 988 1.1 mrg { 989 1.1 mrg int i, j; 990 1.1 mrg int sum; 991 1.1 mrg int *component = scc_graph->component; 992 1.1 mrg int *size = scc_graph->size; 993 1.1 mrg int *pos = scc_graph->pos; 994 1.1 mrg int *sorted = scc_graph->sorted; 995 1.1 mrg int n_component; 996 1.1 mrg 997 1.1 mrg n_component = 0; 998 1.1 mrg for (i = 0; i < n; ++i) { 999 1.1 mrg size[first + i] = 0; 1000 1.1 mrg if (component[first + i] == first + i) 1001 1.1 mrg n_component++; 1002 1.1 mrg else 1003 1.1 mrg component[first + i] = component[component[first + i]]; 1004 1.1 mrg size[component[first + i]]++; 1005 1.1 mrg } 1006 1.1 mrg 1007 1.1 mrg sum = first; 1008 1.1 mrg i = 0; 1009 1.1 mrg for (j = 0; j < n_component; ++j) { 1010 1.1 mrg while (size[first + i] == 0) 1011 1.1 mrg ++i; 1012 1.1 mrg pos[first + i] = sum; 1013 1.1 mrg sum += size[first + i]; 1014 1.1 mrg size[first + j] = size[first + i++]; 1015 1.1 mrg } 1016 1.1 mrg for (i = 0; i < n; ++i) 1017 1.1 mrg sorted[pos[component[first + i]]++] = first + i; 1018 1.1 mrg 1019 1.1 mrg return n_component; 1020 1.1 mrg } 1021 1.1 mrg 1022 1.1 mrg /* Extract out a list of filters for a set node that splits up 1023 1.1 mrg * the graph into "n_component" components. 1024 1.1 mrg * "first" is the initial position in "scc_graph" where information 1025 1.1 mrg * about the components is stored. 1026 1.1 mrg * In particular, the first "n_component" entries of scc_graph->size 1027 1.1 mrg * at this position contain the number of SCCs in each component. 1028 1.1 mrg * The entries of scc_graph->sorted starting at "first" 1029 1.1 mrg * contain the local indices of the SCC in those components. 1030 1.1 mrg */ 1031 1.1 mrg static __isl_give isl_union_set_list *extract_components( 1032 1.1 mrg struct isl_scc_graph *scc_graph, int first, int n_component) 1033 1.1 mrg { 1034 1.1 mrg int i; 1035 1.1 mrg int sum; 1036 1.1 mrg int *size = scc_graph->size; 1037 1.1 mrg int *sorted = scc_graph->sorted; 1038 1.1 mrg isl_ctx *ctx = scc_graph->ctx; 1039 1.1 mrg isl_union_set_list *filters; 1040 1.1 mrg 1041 1.1 mrg filters = isl_union_set_list_alloc(ctx, n_component); 1042 1.1 mrg sum = first; 1043 1.1 mrg for (i = 0; i < n_component; ++i) { 1044 1.1 mrg int n; 1045 1.1 mrg 1046 1.1 mrg n = size[first + i]; 1047 1.1 mrg filters = isl_scc_graph_add_scc_indirect_seq(scc_graph, 1048 1.1 mrg &sorted[sum], n, filters); 1049 1.1 mrg sum += n; 1050 1.1 mrg } 1051 1.1 mrg 1052 1.1 mrg return filters; 1053 1.1 mrg } 1054 1.1 mrg 1055 1.1 mrg /* Detect components in the subgraph consisting of the "n" SCCs 1056 1.1 mrg * with local index starting at "first" and further decompose them, 1057 1.1 mrg * calling isl_schedule_node_compute_finish_band on each 1058 1.1 mrg * of the corresponding clusters. 1059 1.1 mrg * 1060 1.1 mrg * If there is only one SCC, then isl_schedule_node_compute_finish_band 1061 1.1 mrg * can be called directly. 1062 1.1 mrg * Otherwise, determine the components and rearrange the local indices 1063 1.1 mrg * according to component, but preserving the topological order within 1064 1.1 mrg * each component, in scc_graph->sorted. The sizes of the components 1065 1.1 mrg * are stored in scc_graph->size. 1066 1.1 mrg * If there is only one component, it can be further decomposed 1067 1.1 mrg * directly by a call to recurse(). 1068 1.1 mrg * Otherwise, introduce a set node separating the components and 1069 1.1 mrg * call recurse() on each component separately. 1070 1.1 mrg */ 1071 1.1 mrg static __isl_give isl_schedule_node *detect_components( 1072 1.1 mrg struct isl_scc_graph *scc_graph, int first, int n, 1073 1.1 mrg __isl_take isl_schedule_node *node) 1074 1.1 mrg { 1075 1.1 mrg int i; 1076 1.1 mrg int *size = scc_graph->size; 1077 1.1 mrg int *sorted = scc_graph->sorted; 1078 1.1 mrg int n_component; 1079 1.1 mrg int sum; 1080 1.1 mrg isl_union_set_list *filters; 1081 1.1 mrg 1082 1.1 mrg if (n == 1) 1083 1.1 mrg return isl_scc_graph_finish_band(scc_graph, node, first); 1084 1.1 mrg 1085 1.1 mrg if (isl_scc_graph_merge_components(scc_graph, first, n) < 0) 1086 1.1 mrg return isl_schedule_node_free(node); 1087 1.1 mrg 1088 1.1 mrg n_component = isl_scc_graph_sort_components(scc_graph, first, n); 1089 1.1 mrg if (n_component == 1) 1090 1.1 mrg return recurse(scc_graph, &sorted[first], n, node); 1091 1.1 mrg 1092 1.1 mrg filters = extract_components(scc_graph, first, n_component); 1093 1.1 mrg node = isl_schedule_node_insert_set(node, filters); 1094 1.1 mrg 1095 1.1 mrg sum = first; 1096 1.1 mrg for (i = 0; i < n_component; ++i) { 1097 1.1 mrg int n; 1098 1.1 mrg 1099 1.1 mrg n = size[first + i]; 1100 1.1 mrg node = isl_schedule_node_grandchild(node, i, 0); 1101 1.1 mrg node = recurse(scc_graph, &sorted[sum], n, node); 1102 1.1 mrg node = isl_schedule_node_grandparent(node); 1103 1.1 mrg sum += n; 1104 1.1 mrg } 1105 1.1 mrg 1106 1.1 mrg return node; 1107 1.1 mrg } 1108 1.1 mrg 1109 1.1 mrg /* Given a sequence node "node", where the filter at position "child" 1110 1.1 mrg * represents the "n" SCCs with local index starting at "first", 1111 1.1 mrg * detect components in this subgraph and further decompose them, 1112 1.1 mrg * calling isl_schedule_node_compute_finish_band on each 1113 1.1 mrg * of the corresponding clusters. 1114 1.1 mrg */ 1115 1.1 mrg static __isl_give isl_schedule_node *detect_components_at( 1116 1.1 mrg struct isl_scc_graph *scc_graph, int first, int n, 1117 1.1 mrg __isl_take isl_schedule_node *node, int child) 1118 1.1 mrg { 1119 1.1 mrg node = isl_schedule_node_grandchild(node, child, 0); 1120 1.1 mrg node = detect_components(scc_graph, first, n, node); 1121 1.1 mrg node = isl_schedule_node_grandparent(node); 1122 1.1 mrg 1123 1.1 mrg return node; 1124 1.1 mrg } 1125 1.1 mrg 1126 1.1 mrg /* Return the local index of an SCC on which to split "scc_graph". 1127 1.1 mrg * Return scc_graph->n if no suitable split SCC can be found. 1128 1.1 mrg * 1129 1.1 mrg * In particular, look for an SCC that is involved in the largest number 1130 1.1 mrg * of edges. Splitting the graph on such an SCC has the highest chance 1131 1.1 mrg * of exposing independent SCCs in the remaining part(s). 1132 1.1 mrg * There is no point in splitting a chain of nodes, 1133 1.1 mrg * so return scc_graph->n if the entire graph forms a chain. 1134 1.1 mrg */ 1135 1.1 mrg static int best_split(struct isl_scc_graph *scc_graph) 1136 1.1 mrg { 1137 1.1 mrg int i; 1138 1.1 mrg int split = scc_graph->n; 1139 1.1 mrg int split_score = -1; 1140 1.1 mrg 1141 1.1 mrg for (i = 0; i < scc_graph->n; ++i) { 1142 1.1 mrg int n_fwd, n_bwd; 1143 1.1 mrg 1144 1.1 mrg n_fwd = scc_graph->edge_table[i]->n; 1145 1.1 mrg n_bwd = scc_graph->reverse_edge_table[i]->n; 1146 1.1 mrg if (n_fwd <= 1 && n_bwd <= 1) 1147 1.1 mrg continue; 1148 1.1 mrg if (split_score >= n_fwd + n_bwd) 1149 1.1 mrg continue; 1150 1.1 mrg split = i; 1151 1.1 mrg split_score = n_fwd + n_bwd; 1152 1.1 mrg } 1153 1.1 mrg 1154 1.1 mrg return split; 1155 1.1 mrg } 1156 1.1 mrg 1157 1.1 mrg /* Call isl_schedule_node_compute_finish_band on each of the clusters 1158 1.1 mrg * in scc_graph->c and update "node" to arrange for them to be executed 1159 1.1 mrg * in an order possibly involving set nodes that generalizes 1160 1.1 mrg * the topological order determined by the scc fields of the nodes 1161 1.1 mrg * in scc_graph->graph. 1162 1.1 mrg * 1163 1.1 mrg * First try and find a suitable SCC on which to split the graph. 1164 1.1 mrg * If no such SCC can be found then the graph forms a chain and 1165 1.1 mrg * it is handled as such. 1166 1.1 mrg * Otherwise, break up the graph into (at most) three parts, 1167 1.1 mrg * the SCCs before the selected SCC (in the topological order), 1168 1.1 mrg * the selected SCC itself, and 1169 1.1 mrg * the SCCs after the selected SCC. 1170 1.1 mrg * The first and last part (if they exist) are decomposed recursively and 1171 1.1 mrg * the three parts are combined in a sequence. 1172 1.1 mrg * 1173 1.1 mrg * Since the outermost node of the recursive pieces may also be a sequence, 1174 1.1 mrg * these potential sequence nodes are spliced into the top-level sequence node. 1175 1.1 mrg */ 1176 1.1 mrg __isl_give isl_schedule_node *isl_scc_graph_decompose( 1177 1.1 mrg struct isl_scc_graph *scc_graph, __isl_take isl_schedule_node *node) 1178 1.1 mrg { 1179 1.1 mrg int i; 1180 1.1 mrg int split; 1181 1.1 mrg isl_union_set_list *filters; 1182 1.1 mrg 1183 1.1 mrg if (!scc_graph) 1184 1.1 mrg return isl_schedule_node_free(node); 1185 1.1 mrg 1186 1.1 mrg split = best_split(scc_graph); 1187 1.1 mrg 1188 1.1 mrg if (split == scc_graph->n) 1189 1.1 mrg return isl_scc_graph_chain(scc_graph, node); 1190 1.1 mrg 1191 1.1 mrg filters = extract_split_scc(scc_graph, split); 1192 1.1 mrg node = isl_schedule_node_insert_sequence(node, filters); 1193 1.1 mrg 1194 1.1 mrg isl_scc_graph_init_component(scc_graph); 1195 1.1 mrg 1196 1.1 mrg i = 0; 1197 1.1 mrg if (split > 0) 1198 1.1 mrg node = detect_components_at(scc_graph, 0, split, node, i++); 1199 1.1 mrg node = isl_schedule_node_grandchild(node, i++, 0); 1200 1.1 mrg node = isl_scc_graph_finish_band(scc_graph, node, split); 1201 1.1 mrg node = isl_schedule_node_grandparent(node); 1202 1.1 mrg if (split + 1 < scc_graph->n) 1203 1.1 mrg node = detect_components_at(scc_graph, 1204 1.1 mrg split + 1, scc_graph->n - (split + 1), node, i++); 1205 1.1 mrg 1206 1.1 mrg node = isl_schedule_node_sequence_splice_children(node); 1207 1.1 mrg 1208 1.1 mrg return node; 1209 1.1 mrg } 1210