update isl for change in lexicographic optimization
[isa.git] / pn.cc
blobafd4a7337d968d4b79ea68c4ca2c0f6239c8cd7f
1 #include <iostream>
2 #include <set>
3 #include <map>
4 #include <vector>
6 #include <isl/ctx.h>
7 #include <isl/space.h>
8 #include <isl/set.h>
9 #include <isl/map.h>
10 #include <isl/union_map.h>
11 #include <isl/polynomial.h>
12 #include <isl/flow.h>
14 #include <isa/yaml.h>
15 #include <isa/pdg.h>
16 #include "da.h"
17 #include "size.h"
18 extern "C" {
19 #include "isl_util.h"
21 #include "translation.h"
22 #include "pn_options.h"
24 #include "memrchr.h"
26 using pdg::PDG;
27 using namespace std;
28 using namespace da;
29 using namespace size;
31 /* Check whether node is a propagation node
33 * A propagation node simply copies a value from one array to another array.
34 * In principle, a copy node could also copy a value to the same array,
35 * but then we would have to be careful that the node does not recursively
36 * copy values.
37 * Note that the check is incomplete. If a node performs some additional
38 * operations involving only iterators, then this information is not stored
39 * so we may incorrectly conclude that the node is a copy node.
41 static bool propagation_node(pdg::node *node)
43 pdg::statement *s = node->statement;
44 if (s->accesses.size() != 2)
45 return false;
46 if (s->accesses[0]->type != pdg::access::read)
47 return false;
48 if (s->accesses[1]->type != pdg::access::write)
49 return false;
50 if (s->accesses[0]->array == s->accesses[1]->array)
51 return false;
52 if (s->accesses[1]->array->dims.size() != 0)
53 return false;
54 if (s->top_function && s->top_function->name &&
55 strcmp(s->top_function->name->s.c_str(), ""))
56 return false;
57 return true;
60 static pdg::IslMap *join_input(PDG *pdg, pdg::IslMap *left,
61 pdg::IslMap *right)
63 pdg::IslMap *res;
64 isl_ctx *ctx = pdg->get_isl_ctx();
65 isl_map *rel = left->get_isl_map(ctx);
66 isl_map *acc = right->get_isl_map(ctx);
68 acc = isl_map_apply_domain(acc, rel);
70 res = new pdg::IslMap(acc);
72 return res;
75 /* Given a dependence relation um_rel that maps iterations from
76 * a propagation node to the current node and an access relation
77 * from the current node, drop those iterations from the domain
78 * of the access relation that have been propagated, i.e.,
79 * that are in the range of the dependence relation.
81 * The original access relation is destroyed and a new one
82 * is returned, provided the new access relation is not empty.
83 * If it is empty, then a NULL pointer is returned.
85 * Note that the input access relation may not have been specialized
86 * to the domain of the node, i.e., the access relation may have
87 * a universe domain. In that case, the new relation is unlikely
88 * to be empty, but it may end up having a domain that is disjoint
89 * from the domain of the node.
91 static pdg::IslMap *remove_propagated_from_domain(PDG *pdg,
92 pdg::IslMap *um_rel, pdg::IslMap *um_acc)
94 pdg::IslMap *res = NULL;
95 isl_ctx *ctx = pdg->get_isl_ctx();
96 isl_map *rel = um_rel->get_isl_map(ctx);
97 isl_map *acc = um_acc->get_isl_map(ctx);
99 isl_set *rel_ran = isl_map_range(rel);
100 isl_set *acc_dom = isl_map_domain(isl_map_copy(acc));
102 acc_dom = isl_set_subtract(acc_dom, rel_ran);
103 acc = isl_map_intersect_domain(acc, acc_dom);
105 delete um_acc;
107 if (isl_map_is_empty(acc))
108 isl_map_free(acc);
109 else
110 res = new pdg::IslMap(acc);
112 return res;
115 /* Recursively replace old_access inside call by new_access.
117 static void replace_access(pdg::function_call *call, pdg::access *old_access,
118 pdg::call_or_access *new_coa)
120 for (int i = 0; i < call->arguments.size(); ++i) {
121 pdg::call_or_access *coa = call->arguments[i];
122 if (coa->type == pdg::call_or_access::t_call)
123 replace_access(coa->call, old_access, new_coa);
124 if (coa->type == pdg::call_or_access::t_access &&
125 coa->access == old_access) {
126 *coa = *new_coa;
127 break;
132 /* Replace old_access inside s by new_access.
133 * If empty is not set, then new_access only replaces part of
134 * old_access. This means that old_access is kept in the list
135 * of accesses and that in the parse tree of the statement,
136 * old_access is replaced by a new virtual function call
137 * with old_access and new_access as arguments.
139 static void replace_access(pdg::statement *s, pdg::access *old_access,
140 pdg::access *new_access, bool empty)
142 pdg::call_or_access coa;
144 if (empty)
145 s->accesses.erase(old_access);
146 s->accesses.push_back(new_access);
148 if (!s->top_function)
149 return;
151 if (empty) {
152 coa.type = pdg::call_or_access::t_access;
153 coa.access = new_access;
154 } else {
155 pdg::call_or_access *old_coa, *new_coa;
156 coa.type = pdg::call_or_access::t_call;
157 coa.call = new pdg::function_call;
158 coa.call->name = new str(string("#PHI"));
159 old_coa = new pdg::call_or_access;
160 old_coa->type = pdg::call_or_access::t_access;
161 old_coa->access = old_access;
162 coa.call->arguments.push_back(old_coa);
163 new_coa = new pdg::call_or_access;
164 new_coa->type = pdg::call_or_access::t_access;
165 new_coa->access = new_access;
166 coa.call->arguments.push_back(new_coa);
168 replace_access(s->top_function, old_access, &coa);
171 static void clear_dependences(PDG *pdg)
173 for (int j = 0; j < pdg->dependences.size(); ++j) {
174 pdg::dependence *dep = pdg->dependences[j];
175 delete dep->controlled_relation;
176 delete dep->relation;
177 delete dep;
179 pdg->dependences.resize(0);
182 /* Check if there is any node that simply copies the value from an array
183 * to a scalar. If so, perform dependence analysis on the scalar
184 * and replaces read access to the scalar that depend on writes from
185 * a propagation node to reads from the propagated array.
186 * In particular, the propagated iterations are removed from the access
187 * relation and replaced by an access to the propagated array.
188 * Finally, the propagation node is removed.
190 static void copy_propagation(PDG* pdg)
192 std::set<pdg::node *> to_remove_n;
193 for (int i = 0; i < pdg->nodes.size(); ++i) {
194 pdg::node *node = pdg->nodes[i];
195 pdg::statement *s = node->statement;
196 if (!propagation_node(node))
197 continue;
198 pdg::array *a = s->accesses[1]->array;
199 find_deps(pdg, a, flow);
200 std::set<pdg::access *> to_remove;
201 for (int j = 0; j < pdg->dependences.size(); ++j) {
202 pdg::dependence *dep = pdg->dependences[j];
203 if (dep->controlled_relation)
204 continue;
205 assert(dep->type == pdg::dependence::flow);
206 assert(dep->from != dep->to);
207 if (!propagation_node(dep->from))
208 continue;
209 to_remove_n.insert(dep->from);
210 pdg::IslMap *access_map = dep->from->statement->accesses[0]->map;
211 pdg::IslMap *prop_access = join_input(pdg, dep->relation, access_map);
212 access_map = dep->to_access->map;
213 access_map = remove_propagated_from_domain(pdg, dep->relation,
214 access_map);
215 dep->to_access->map = access_map;
216 bool empty = !access_map;
217 pdg::access *access = new pdg::access;
218 access->nr = dep->to_access->nr;
219 access->array = dep->from->statement->accesses[0]->array;
220 access->type = pdg::access::read;
221 access->map = prop_access;
222 replace_access(dep->to->statement, dep->to_access, access, empty);
223 if (empty)
224 to_remove.insert(dep->to_access);
226 std::set<pdg::access *>::iterator it;
227 for (it = to_remove.begin(); it != to_remove.end(); ++it) {
228 (*it)->array = NULL;
229 (*it)->free();
230 delete (*it);
232 clear_dependences(pdg);
234 if (to_remove_n.size() == 0)
235 return;
236 std::set<pdg::node *>::iterator itn;
237 for (itn = to_remove_n.begin(); itn != to_remove_n.end(); ++itn) {
238 (*itn)->statement->accesses[0]->array = NULL;
239 (*itn)->statement->accesses[1]->array = NULL;
240 (*itn)->free();
241 delete (*itn);
242 pdg->nodes.erase(*itn);
244 for (int i = 0; i < pdg->nodes.size(); ++i)
245 pdg->nodes[i]->nr = i;
248 /* Check whether dep writes and reads from consecutive iterations of
249 * the same domain.
250 * We check this property by testing whether any other read for the
251 * same access occurs in between.
253 bool is_consecutive_dep(PDG *pdg, pdg::dependence *dep, isl_map *map)
255 isl_ctx *ctx = pdg->get_isl_ctx();
256 assert(dep->to == dep->from);
257 for (int i = 0; i < pdg->dependences.size(); ++i) {
258 pdg::dependence *other_dep = pdg->dependences[i];
259 if (other_dep == dep)
260 continue;
261 if (other_dep->to != dep->to)
262 continue;
263 if (other_dep->to_access != dep->to_access)
264 continue;
265 isl_map *other_map = other_dep->relation->get_isl_map(ctx);
266 bool consec = isl_is_consecutive_dep(map, other_map);
267 isl_map_free(other_map);
268 if (!consec)
269 return false;
271 return true;
274 /* An auxiliary class that keeps a reference to an isl_map
275 * and frees it when it goes out of scope.
277 struct temp_map {
278 isl_map * const map;
279 temp_map(isl_map *m) : map(m) {}
280 operator isl_map *() const { return map; }
281 ~temp_map() {
282 isl_map_free(map);
286 /* Set *user to qp of the first call, assuming *user was initialized to NULL.
287 * If this function is called more than once, then return isl_stat_error.
289 static isl_stat extract_single(__isl_take isl_set *set,
290 __isl_take isl_qpolynomial *qp, void *user)
292 isl_qpolynomial **res = (isl_qpolynomial **) user;
294 isl_set_free(set);
296 if (*res) {
297 isl_qpolynomial_free(qp);
298 return isl_stat_error;
301 *res = qp;
302 return isl_stat_ok;
305 /* Check if we can use a shift register for the self-dependence dep
306 * on the domain D.
307 * If yes, return the required size of the shift register.
308 * If no, return NULL.
310 * We assume that the register is shifted on every iteration of D.
311 * If the number of shifts between any pair of writes and reads is
312 * constant, then we can use a shift register.
313 * Note that the size of the shift register may be larger than
314 * that of the FIFO, since there may be iterations of the domain
315 * between corresponding writes and reads where nothing is written
316 * to or read from the shift register.
318 * If "ref" is a wrapped map, then the iteration domain
319 * is in the domain of that map.
321 static size::enumerator *shift_register_size(pdg::PDG *pdg,
322 __isl_take isl_set *ref, __isl_take isl_map *dep)
324 isl_space *dims;
325 isl_set *dep_set;
326 isl_map *read_after_ref;
327 isl_map *write_before_ref;
328 isl_map *ref_between;
329 isl_pw_qpolynomial *pwqp;
330 isl_set *universe;
331 isl_qpolynomial *qp;
332 unsigned dim;
334 if (isl_set_is_wrapping(ref))
335 ref = isl_map_domain(isl_set_unwrap(ref));
337 dim = isl_set_dim(ref, isl_dim_set);
338 dep = isl_map_move_dims(dep, isl_dim_in, dim, isl_dim_out, 0, dim);
339 dep_set = isl_map_domain(dep);
341 read_after_ref = isl_map_lex_ge(isl_set_get_space(ref));
342 read_after_ref = isl_map_insert_dims(read_after_ref, isl_dim_in, 0, dim);
343 write_before_ref = isl_map_lex_lt(isl_set_get_space(ref));
344 write_before_ref = isl_map_add_dims(write_before_ref, isl_dim_in, dim);
345 ref_between = isl_map_intersect(read_after_ref, write_before_ref);
347 ref_between = isl_map_intersect_range(ref_between, ref);
348 ref_between = isl_map_intersect_domain(ref_between,
349 isl_set_copy(dep_set));
351 pwqp = isl_map_card(ref_between);
353 pwqp = isl_pw_qpolynomial_gist(pwqp, dep_set);
355 pwqp = isl_pw_qpolynomial_coalesce(pwqp);
357 qp = NULL;
358 if (isl_pw_qpolynomial_foreach_piece(pwqp, &extract_single, &qp) < 0 ||
359 !qp ||
360 isl_qpolynomial_involves_dims(qp, isl_dim_in, 0, dim + dim)) {
361 isl_qpolynomial_free(qp);
362 isl_pw_qpolynomial_free(pwqp);
363 return NULL;
365 isl_pw_qpolynomial_free(pwqp);
367 qp = isl_qpolynomial_project_domain_on_params(qp);
368 universe = isl_set_universe(isl_qpolynomial_get_domain_space(qp));
369 pwqp = isl_pw_qpolynomial_alloc(universe, qp);
371 return new size::enumerator(pwqp, pdg);
374 /* isl_access_level_before function used in a context where there
375 * is a single iteration domain. The order is given by the order
376 * of the accesses passed through first and second.
377 * If the first access precedes the second, we return 2 * d + 1,
378 * where d is the dimension of the iteration domain, and otherwise 2 * d.
380 static int precedes_access(void *first, void *second)
382 pdg::access *access1 = (pdg::access *) first;
383 pdg::access *access2 = (pdg::access *) second;
384 int d = isl_map_dim(access1->map->map, isl_dim_in);
386 return 2 * d + (access1->nr < access2->nr);
389 /* Return true if all input dimensions are constrained to be equal to the
390 * corresponding output dimensions.
392 static bool is_identity_map(__isl_keep isl_map *map)
394 int is_id;
395 isl_space *space = isl_map_get_space(map);
396 isl_map *id = isl_map_identity(space);
398 is_id = isl_map_is_subset(map, id);
400 isl_map_free(id);
402 return is_id;
405 /* Set buf (of size buf_len) to the prefix of control variables
406 * that correspond to the from and to access of the given "dep"
407 * and return the length of the prefix.
409 static size_t set_local_control_name(char *buf, size_t buf_len,
410 pdg::dependence *dep)
412 snprintf(buf, buf_len, "__last_%s_%d_%s_%d",
413 dep->from->name->s.c_str(), dep->from_access->nr,
414 dep->to->name->s.c_str(), dep->to_access->nr);
415 return strlen(buf);
418 /* Given the name of a binding variable, reset the part that refers
419 * to the sink access by "nr".
421 * The original name is of the form
423 * __last_ND_<source node>_<source access>_ND_<sink node>_<sink access>_*
425 * We simply replace the <sink access> by <nr>.
427 static str *replace_to_access(isl_ctx *ctx, str *id, int nr)
429 const char *name;
430 const char *suffix;
431 const char *infix;
432 char *replaced;
433 size_t len;
434 str *s;
436 name = id->s.c_str();
437 assert(name);
438 suffix = strrchr(name, '_');
439 assert(suffix);
440 infix = (const char *) memrchr(name, '_', suffix - name);
441 assert(infix);
442 len = infix + 1 - name + strlen(suffix) + 20;
443 replaced = isl_alloc_array(ctx, char, len);
444 assert(replaced);
445 len = infix + 1 - name;
446 memcpy(replaced, name, len);
447 snprintf(replaced + len, 20, "%d", nr);
448 len += strlen(replaced + len);
449 strcpy(replaced + len, suffix);
451 s = new str(replaced);
452 free(replaced);
454 return s;
457 /* For each element of controls, replace the part of the name that
458 * refers to the sink access by "nr" and collect the results in
459 * renamed_controls.
461 static void replace_to_access(isl_ctx *ctx, seq<str> &renamed_controls,
462 seq<str> &controls, int nr)
464 for (int i = 0; i < controls.size(); ++i)
465 renamed_controls.push_back(replace_to_access(ctx,
466 controls[i], nr));
469 /* Is the i-th parameter of "map" of the form __last_*
470 * but not of the form local_control*?
472 static bool is_foreign_control(__isl_keep isl_map *map, int i,
473 const char *local_control, size_t len)
475 const char *name;
476 const char *prefix = "__last_";
477 size_t prefix_len = strlen(prefix);
479 if (!isl_map_has_dim_id(map, isl_dim_param, i))
480 return false;
481 name = isl_map_get_dim_name(map, isl_dim_param, i);
482 if (strncmp(name, prefix, prefix_len))
483 return false;
484 return strncmp(name, local_control, len) != 0;
487 /* Remove from "dep" all those parameters that are of the form __last_*
488 * but not of the form local_control* and return the result.
490 static __isl_give isl_map *remove_foreign_controls(__isl_take isl_map *dep,
491 const char *local_control, size_t len)
493 int n_param;
495 n_param = isl_map_dim(dep, isl_dim_param);
496 for (int i = n_param - 1; i >= 0; --i) {
497 if (!is_foreign_control(dep, i, local_control, len))
498 continue;
499 dep = isl_map_project_out(dep, isl_dim_param, i, 1);
501 dep = isl_map_coalesce(dep);
503 return dep;
506 /* Is the i-th parameter of "map" a control, i.e., a parameter
507 * introduced by convert_writer()?
508 * In particular, is the parameter of the form __last_*?
510 static bool is_control(__isl_keep isl_map *map, int i)
512 const char *name;
513 const char *prefix = "__last_";
514 size_t prefix_len = strlen(prefix);
516 if (!isl_map_has_dim_id(map, isl_dim_param, i))
517 return false;
518 name = isl_map_get_dim_name(map, isl_dim_param, i);
519 return strncmp(name, prefix, prefix_len) == 0;
522 /* Remove all parameters that were introduced by convert_writer().
524 static __isl_give isl_map *remove_all_controls(__isl_take isl_map *dep)
526 int n_param;
528 n_param = isl_map_dim(dep, isl_dim_param);
529 for (int i = n_param - 1; i >= 0; --i) {
530 if (!is_control(dep, i))
531 continue;
532 dep = isl_map_project_out(dep, isl_dim_param, i, 1);
534 dep = isl_map_coalesce(dep);
536 return dep;
539 struct add_reuse_data {
540 PDG *pdg;
541 pdg::dependence *dep;
544 extern "C" {
545 static isl_stat add_reuse(__isl_take isl_map *dep_rel, int must,
546 void *dep_user, void *user);
549 /* Add a reuse dependence with dependence relation "dep_rel" to
550 * data->pdg->dependences.
551 * data->dep corresponds to the original dependence that is reusing
552 * some value that was previously used by "propagate_access", from
553 * the same node.
554 * Since "dep_rel" was obtained from a relation with local
555 * control variables, we need to remove them to obtain the
556 * dependence relation on the reuse dependence.
558 * If we are reusing control variables, then we need to rename
559 * the from_control to refer to the access where we are reusing
560 * the control variables from.
562 * If the dependence relations maps iterations to themselves, then
563 * we mark the new reuse dependence as a wire.
565 static isl_stat add_reuse(__isl_take isl_map *dep_rel, int must, void *dep_user,
566 void *user)
568 pdg::access *propagate_access = (pdg::access *) dep_user;
569 add_reuse_data *data = (add_reuse_data *) user;
570 pdg::dependence *reuse_dep;
571 isl_ctx *ctx = isl_map_get_ctx(dep_rel);
573 reuse_dep = new pdg::dependence;
574 reuse_dep->array = data->dep->array;
575 replace_to_access(ctx, reuse_dep->from_controls,
576 data->dep->from_controls, propagate_access->nr);
577 reuse_dep->to_controls = data->dep->to_controls;
578 reuse_dep->from = data->dep->to;
579 reuse_dep->to = data->dep->to;
580 reuse_dep->from_access = propagate_access;
581 reuse_dep->to_access = data->dep->to_access;
582 if (reuse_dep->from == reuse_dep->to && is_identity_map(dep_rel))
583 reuse_dep->type = pdg::dependence::pn_wire;
584 else
585 reuse_dep->type = data->dep->type;
586 if (data->dep->controlled_relation) {
587 pdg::IslMap *cr = data->dep->controlled_relation;
588 isl_set *dom = isl_map_range(cr->get_isl_map());
589 isl_map *control_rel = isl_map_copy(dep_rel);
590 control_rel = isl_map_intersect_range(control_rel, dom);
591 reuse_dep->controlled_relation = new pdg::IslMap(control_rel);
593 dep_rel = remove_all_controls(dep_rel);
594 reuse_dep->relation = new pdg::IslMap(dep_rel);
595 data->pdg->dependences.push_back(reuse_dep);
597 return isl_stat_ok;
600 /* Detect reuse among the dependences in "deps", adding split off
601 * dependences to pdg->dependences.
602 * Each of the dependences in "deps" originates from the same
603 * write access and ends in the same node.
605 * We look for values, i.e., iterations of the write access,
606 * that are used several times. To do so, we perform dependence
607 * analysis on the inverted dependence relations. That is,
608 * we use these inverted dependence relations as "access relations",
609 * accessing iterations of the write access.
610 * We consider each dependence in turn as a "read", each time taking
611 * all dependences as writes.
612 * In the result of such a dependence analysis, the "uninitialized reads"
613 * correspond to the first use of a result from the original write access,
614 * while all the "dependences" corespond to a propagation of a value
615 * from one original read access to another original read access.
617 * If the dependence has a controlled_relation, then we use this
618 * controlled_relation as the "access relation" after removing all
619 * the foreign controls. This ensures that we only reuse data if
620 * the last iteration hasn't changed.
621 * After restricting the range of the controlled_relation based on
622 * the "uninitialized reads", we recompute the uncontrolled relation
623 * from this result.
625 * If there is only one dependence in "deps" and if that dependence
626 * is single-valued, then obviously there can be no reuse, so we skip
627 * the analysis.
629 * We currently assume that none of the accesses has an extended_relation.
631 static void detect_reuse(PDG *pdg, std::vector<pdg::dependence *> &deps)
633 add_reuse_data data = { pdg };
634 char buf[120];
635 size_t len;
637 if (deps.size() == 1 &&
638 isl_map_is_single_valued(deps[0]->relation->map))
639 return;
641 for (int i = 0; i < deps.size(); ++i) {
642 isl_access_info *ai;
643 isl_flow *flow;
644 isl_set *first;
645 isl_map *local;
646 pdg::IslMap *rel;
648 assert(!deps[i]->extended_relation);
650 if (deps[i]->controlled_relation) {
651 local = deps[i]->controlled_relation->get_isl_map();
652 len = set_local_control_name(buf, sizeof(buf), deps[i]);
653 local = remove_foreign_controls(local, buf, len);
654 } else
655 local = deps[i]->relation->get_isl_map();
656 local = isl_map_reverse(local);
658 data.dep = deps[i];
659 ai = isl_access_info_alloc(isl_map_copy(local),
660 deps[i]->to_access, &precedes_access, deps.size());
661 for (int j = 0; j < deps.size(); ++j) {
662 isl_map *map;
663 if (i == j) {
664 map = isl_map_copy(local);
665 } else {
666 map = deps[j]->relation->get_isl_map();
667 map = isl_map_reverse(map);
669 ai = isl_access_info_add_source(ai, map,
670 1, deps[j]->to_access);
672 flow = isl_access_info_compute_flow(ai);
673 isl_flow_foreach(flow, &add_reuse, &data);
674 first = isl_map_domain(isl_flow_get_no_source(flow, 1));
675 isl_flow_free(flow);
677 rel = deps[i]->relation;
678 if (deps[i]->controlled_relation) {
679 pdg::IslMap *cr = deps[i]->controlled_relation;
680 cr->map = isl_map_intersect_range(cr->map, first);
681 isl_map_free(rel->map);
682 rel->map = remove_all_controls(isl_map_copy(cr->map));
683 } else
684 rel->map = isl_map_intersect_range(rel->map, first);
686 isl_map_free(local);
690 /* Has this dependence been created during the detection
691 * of multiple assignments? In particular, does this dependence
692 * propagate the values in the source.
694 static bool is_multi_assignment_propagation(pdg::dependence *dep)
696 return dep->to_access == dep->from_access &&
697 dep->to_access->type == pdg::access::write;
700 typedef std::pair<pdg::access *, pdg::node *> an_pair;
701 typedef std::pair<int, an_pair> nan_triple;
703 struct nan_triple_cmp {
704 bool operator()(nan_triple t1, nan_triple t2) const {
705 if (t1.first != t2.first)
706 return t1.first < t2.first;
707 if (t1.second.first->nr != t2.second.first->nr)
708 return t1.second.first->nr < t2.second.first->nr;
709 return t1.second.second->nr < t2.second.second->nr;
713 typedef std::map<nan_triple, std::vector<pdg::dependence *>, nan_triple_cmp>
714 nan2deps;
716 /* Detect reuse of the same value (originating from the same
717 * write access) within a node and split the corresponding dependence
718 * into part of the original dependences that use the value for
719 * the first time and internal dependences that propagate the value.
721 * If a scheduling is applied that changes the order of the iterations
722 * within a given node, then this scheduling should be performed
723 * before the reuse detection.
725 * We first collect the dependences that originate in a given access
726 * and end up in a given node and then process each such collection
727 * in turn, in an order that does not depend on pointer values.
728 * While collecting dependences, we skip those that correspond
729 * to the propagation of multiple assignments to the next potential
730 * assignment.
732 * Dependences that propagate data (those that have a dep->array)
733 * are treated separately from those that propagate control.
735 * If the user has turned off reuse detection, then we do nothing.
737 static void detect_reuse(PDG *pdg, struct pn_options *options)
739 nan2deps access_deps;
740 nan2deps control_deps;
741 nan2deps::iterator it;
743 if (!options->reuse)
744 return;
746 for (int i = 0; i < pdg->dependences.size(); ++i) {
747 pdg::dependence *dep = pdg->dependences[i];
748 if (dep->type == pdg::dependence::uninitialized)
749 continue;
750 if (is_multi_assignment_propagation(dep))
751 continue;
752 an_pair p(dep->from_access, dep->to);
753 nan_triple t(dep->from->nr, p);
754 if (dep->array)
755 access_deps[t].push_back(dep);
756 else
757 control_deps[t].push_back(dep);
760 for (it = access_deps.begin(); it != access_deps.end(); ++it)
761 detect_reuse(pdg, it->second);
762 for (it = control_deps.begin(); it != control_deps.end(); ++it)
763 detect_reuse(pdg, it->second);
766 /* isl_access_level_before function used in a context where the
767 * iteration domains live in a common space. We therefore just
768 * need to retun 2 * the dimension of this space, which is stored
769 * in *first (and *second).
771 static int common_space(void *first, void *second)
773 int depth = *(int *) first;
774 return 2 * depth;
777 /* Assign dep to *user. This function is expected to be called
778 * exactly once.
780 static isl_stat extract_dep(__isl_take isl_map *dep, int must,
781 void *dep_user, void *user)
783 isl_map **map_p = (isl_map **) user;
785 *map_p = dep;
787 return isl_stat_ok;
790 /* Is the i-th parameter of "set" of the form __last_*
791 * but not of the form local_control*?
793 static bool is_foreign_control(__isl_keep isl_set *set, int i,
794 const char *local_control, size_t len)
796 const char *name;
797 const char *prefix = "__last_";
798 size_t prefix_len = strlen(prefix);
800 if (!isl_set_has_dim_id(set, isl_dim_param, i))
801 return false;
802 name = isl_set_get_dim_name(set, isl_dim_param, i);
803 if (strncmp(name, prefix, prefix_len))
804 return false;
805 return strncmp(name, local_control, len) != 0;
808 /* Does "set" have any parameters of the form __last_*
809 * that are not of the form local_control*?
811 static __isl_give isl_set *remove_foreign_controls(__isl_take isl_set *set,
812 const char *local_control, size_t len)
814 int n_param;
816 n_param = isl_set_dim(set, isl_dim_param);
817 for (int i = n_param - 1; i >= 0; --i) {
818 if (!is_foreign_control(set, i, local_control, len))
819 continue;
820 set = isl_set_project_out(set, isl_dim_param, i, 1);
822 set = isl_set_coalesce(set);
824 return set;
827 /* Given a dependence such that the dependence relation
828 * is not injective, split the dependence into two parts,
829 * one that propagates the value from a potential source iteration
830 * to the next potential source iteration and one that sends
831 * the data from the final potential source iteration to the sink
832 * iteration.
834 * The dependence may either be a control dependence, propagating
835 * control variables, or a data dependence, in which case it has
836 * a controlled_relation and it is the uncontrolled relation that
837 * is not injective.
839 * To obtain the last potential source iteration, we simply
840 * compute the lexicographic maximum of all potential source iterations.
842 * To obtain the dependence from one potential source iteration
843 * to the next potential source iteration, we apply
844 * dependence analysis on the dependence relation.
845 * In particular, we need a mapping from source iterations to
846 * the next source iteration associated to the same sink iteration,
847 * so we simply treat the original dependence relation as an access relation.
849 * The mapping to the next potential source should not have any controls.
850 * If the input dependence is a control dependence, then it is propagating
851 * control variables itself. If it is a data dependence, then we want
852 * to propagate values to the next potential source independently of
853 * any control.
855 * The constraints on the controls for the dependence from the final
856 * potential source iteration should be the same as those on the
857 * original relation, when seen from the destination node.
859 * We currently assume that there is no extended relation associated
860 * to the dependence.
862 static void split_multi_assignment(PDG *pdg, pdg::dependence *dep)
864 isl_set *dom;
865 isl_map *last;
866 isl_map *next = NULL;
867 isl_access_info *ai;
868 isl_flow *flow;
869 int depth;
870 pdg::dependence *next_dep;
871 char buf[120];
872 size_t len;
874 assert(!dep->extended_relation);
876 len = set_local_control_name(buf, sizeof(buf), dep);
878 depth = isl_map_dim(dep->relation->map, isl_dim_in);
879 ai = isl_access_info_alloc(isl_map_copy(dep->relation->map),
880 &depth, &common_space, 1);
881 ai = isl_access_info_add_source(ai, isl_map_copy(dep->relation->map),
882 1, &depth);
883 flow = isl_access_info_compute_flow(ai);
884 isl_flow_foreach(flow, &extract_dep, &next);
885 isl_flow_free(flow);
887 last = isl_map_copy(dep->relation->map);
888 last = isl_map_reverse(isl_map_lexmax(isl_map_reverse(last)));
890 next_dep = new pdg::dependence;
891 next_dep->array = dep->array;
892 next_dep->from_controls = dep->from_controls;
893 next_dep->to_controls = dep->to_controls;
894 next_dep->type = dep->type;
895 next_dep->from = dep->from;
896 next_dep->to = dep->from;
897 next_dep->from_access = dep->from_access;
898 next_dep->to_access = dep->from_access;
899 next_dep->relation = new pdg::IslMap(next);
900 pdg->dependences.push_back(next_dep);
902 dep->relation->map = isl_map_intersect(dep->relation->map, last);
903 if (dep->controlled_relation)
904 dep->controlled_relation->map =
905 isl_map_intersect_range(isl_map_copy(dep->relation->map),
906 isl_map_range(dep->controlled_relation->map));
909 /* If any sink iteration has more than one potential source
910 * iteration, we split off the propagation of the data on the from
911 * node from the transfer of the data to the to node.
913 * We only perform this operation here on (data) dependences
914 * with a "controlled_relation". The corresponding control dependence
915 * has already been handled from within extract_control_dependence.
916 * Other data dependences have an exact dependence relation and
917 * can therefore not exhibit multiple assignments.
919 static void split_multi_assignment(PDG *pdg)
921 for (int i = 0; i < pdg->dependences.size(); ++i) {
922 pdg::dependence *dep = pdg->dependences[i];
923 if (!dep->controlled_relation)
924 continue;
925 if (isl_map_is_injective(dep->relation->map))
926 continue;
927 split_multi_assignment(pdg, dep);
931 /* Does "dep" have any parameters of the form __last_*?
933 static bool has_controls(__isl_keep isl_map *dep)
935 int n_param;
936 const char *prefix = "__last_";
937 size_t prefix_len = strlen(prefix);
939 n_param = isl_map_dim(dep, isl_dim_param);
940 for (int i = 0; i < n_param; ++i) {
941 const char *name;
943 if (!isl_map_has_dim_id(dep, isl_dim_param, i))
944 continue;
945 name = isl_map_get_dim_name(dep, isl_dim_param, i);
946 if (!strncmp(name, prefix, prefix_len))
947 return true;
950 return false;
953 /* Is the i-th parameter of "map" of the form local_control*?
954 * "len" is the length of "local_control".
956 static bool is_local_control(__isl_keep isl_map *map, int i,
957 const char *local_control, size_t len)
959 const char *name;
961 if (!isl_map_has_dim_id(map, isl_dim_param, i))
962 return false;
963 name = isl_map_get_dim_name(map, isl_dim_param, i);
964 return strncmp(name, local_control, len) == 0;
967 /* Does "dep" have any parameters of the form __last_*
968 * that are not of the form local_control*?
970 static bool has_foreign_controls(__isl_keep isl_map *dep,
971 const char *local_control, size_t len)
973 int n_param;
975 n_param = isl_map_dim(dep, isl_dim_param);
976 for (int i = 0; i < n_param; ++i)
977 if (is_foreign_control(dep, i, local_control, len))
978 return true;
980 return false;
983 /* Does "dep" have any parameters of the form local_control*?
984 * "len" is the length of "local_control".
986 static bool has_local_controls(__isl_keep isl_map *dep,
987 const char *local_control, size_t len)
989 int n_param;
991 n_param = isl_map_dim(dep, isl_dim_param);
992 for (int i = 0; i < n_param; ++i)
993 if (is_local_control(dep, i, local_control, len))
994 return true;
996 return false;
999 /* Extract a control dependence from a dependence with a controlled_relation.
1000 * The control dependence transfers the values of the control variables
1001 * that correspond to the given dependence, i.e., those that correspond
1002 * to the from and to access of the dependence.
1003 * We therefore don't need to do anything if the controlled_relation
1004 * only involves foreign controls.
1006 * from_controls and to_controls are set from the local control variables
1007 * in dep->controlled_relation.
1009 * The uncontrolled dependence relation may not be injective,
1010 * in which case the initial dependence relation on the control
1011 * dependence is also non-injective. In such cases, the control
1012 * dependence is split using split_multi_assignment in two parts,
1013 * one that propagate the current value of the controls to the next
1014 * iteration of the source and one that sends the final values to the sink.
1015 * The data dependence is split later on.
1017 static void extract_control_dependence(PDG *pdg, pdg::dependence *dep)
1019 pdg::dependence *control;
1020 char buf[120];
1021 size_t len;
1022 int n_param;
1023 isl_map *rel;
1025 len = set_local_control_name(buf, sizeof(buf), dep);
1026 rel = dep->controlled_relation->map;
1027 if (!has_local_controls(rel, buf, len))
1028 return;
1029 n_param = isl_map_dim(rel, isl_dim_param);
1031 control = new pdg::dependence;
1032 control->type = dep->type;
1033 control->from = dep->from;
1034 control->to = dep->to;
1035 control->from_access = dep->from_access;
1036 control->to_access = dep->to_access;
1037 control->relation = new pdg::IslMap(dep->relation->get_isl_map());
1038 for (int i = 0; i < n_param; ++i) {
1039 const char *name;
1040 if (!isl_map_has_dim_id(rel, isl_dim_param, i))
1041 continue;
1042 name = isl_map_get_dim_name(rel, isl_dim_param, i);
1043 if (strncmp(name, buf, len) != 0)
1044 continue;
1045 control->from_controls.push_back(new str(name));
1046 control->to_controls.push_back(new str(name));
1048 pdg->dependences.push_back(control);
1050 if (isl_map_is_injective(control->relation->map))
1051 return;
1052 split_multi_assignment(pdg, control);
1055 /* Extract a control dependence from each dependence with a controlled_relation.
1057 static void extract_control_dependences(PDG *pdg)
1059 int n_dep = pdg->dependences.size();
1061 for (int i = 0; i < n_dep; ++i) {
1062 pdg::dependence *dep = pdg->dependences[i];
1063 if (!dep->controlled_relation)
1064 continue;
1065 extract_control_dependence(pdg, dep);
1069 /* Split off the communication of data, along with the corresponding
1070 * controls, from selecting the data based on other controls.
1071 * "dep" is modified to only refer to the controls that correspond
1072 * to the given from and to access and an extra wire is introduced
1073 * to select the data.
1074 * If "dep" corresponds to a propagation from one potential source
1075 * to the next potential source, then it already only refers to
1076 * "local" controls. We handle this case separately so that we
1077 * don't have to add a special case to set_local_control_name
1078 * for setting up the right name for local controls on such dependences.
1080 * A new virtual access is created to act as the target of the modified
1081 * communication dependence and the source of the selection dependence.
1082 * If the input "dep" did not refer to the corresponding controls,
1083 * then the output "dep" does not refer to any control and
1084 * controlled_relation is cleared.
1086 static void split_wire(PDG *pdg, pdg::dependence *dep)
1088 isl_space *space;
1089 isl_set *dom;
1090 isl_map *rel;
1091 isl_map *id;
1092 pdg::dependence *wire;
1093 pdg::access *access;
1094 char buf[120];
1095 size_t len;
1097 if (is_multi_assignment_propagation(dep))
1098 return;
1100 assert(!dep->extended_relation);
1102 rel = dep->controlled_relation->map;
1103 len = set_local_control_name(buf, sizeof(buf), dep);
1105 if (!has_foreign_controls(rel, buf, len))
1106 return;
1108 space = isl_map_get_space(dep->controlled_relation->map);
1109 space = isl_space_range(space);
1110 space = isl_space_map_from_set(space);
1111 id = isl_map_identity(space);
1112 dom = isl_map_range(isl_map_copy(dep->controlled_relation->map));
1113 id = isl_map_intersect_domain(id, dom);
1115 access = new pdg::access;
1116 access->array = dep->to_access->array;
1117 access->nr = dep->to->statement->accesses.size();
1118 dep->to->statement->accesses.push_back(access);
1120 wire = new pdg::dependence;
1121 wire->array = dep->array;
1122 wire->type = pdg::dependence::pn_wire;
1123 wire->from = dep->to;
1124 wire->to = dep->to;
1125 wire->from_access = access;
1126 wire->to_access = dep->to_access;
1127 wire->relation = new pdg::IslMap(id);
1128 pdg->dependences.push_back(wire);
1130 dep->to_access = access;
1131 dep->controlled_relation->map = remove_foreign_controls(rel, buf, len);
1132 if (!has_controls(dep->controlled_relation->map)) {
1133 delete dep->controlled_relation;
1134 dep->controlled_relation = NULL;
1138 /* If the dependence involves "foreign" controls, i.e., controls
1139 * that correspond to other dependences, then we split off
1140 * the communication of the data (along with the "local" controls)
1141 * from the selection of the data based on the foreign controls.
1143 static void split_wires(PDG *pdg)
1145 for (int i = 0; i < pdg->dependences.size(); ++i) {
1146 pdg::dependence *dep = pdg->dependences[i];
1147 if (!dep->controlled_relation)
1148 continue;
1149 split_wire(pdg, dep);
1153 static void schedule(PDG *pdg, struct pn_options *options)
1155 translate(pdg, options->move);
1158 /* Compute the size of the dependence "dep" with scheduled dependence
1159 * relation "dep_map".
1161 * If "dep" is of type pn_union, then it may contains parts that read
1162 * from the channel in the same iteration. We therefore need to recombine
1163 * the dependence relations of those parts, but separate them apart.
1164 * In particular, we add an extra inner dimension with a fixed value
1165 * corresponding to the index of the dependence.
1167 static size::enumerator *compute_size(pdg::PDG *pdg, pdg::dependence *dep,
1168 __isl_take isl_map *dep_map, pn_options *options)
1170 dep_map = isl_map_copy(dep_map);
1171 if (dep->type == pdg::dependence::pn_union) {
1172 isl_space *space = isl_map_get_space(dep_map);
1173 int n_in, n_out;
1175 n_in = isl_space_dim(space, isl_dim_in);
1176 n_out = isl_space_dim(space, isl_dim_out);
1177 space = isl_space_add_dims(space, isl_dim_in, 1);
1178 space = isl_space_add_dims(space, isl_dim_out, 1);
1179 isl_map_free(dep_map);
1180 dep_map = isl_map_empty(space);
1181 for (int i = 0; i < pdg->dependences.size(); ++i) {
1182 pdg::dependence *part = pdg->dependences[i];
1183 isl_map *map_i;
1185 if (part->type != pdg::dependence::pn_part)
1186 continue;
1187 if (part->container != dep)
1188 continue;
1189 map_i = part->relation->get_isl_map();
1190 map_i = isl_map_intersect_params(map_i,
1191 pdg->get_context_isl_set());
1192 map_i = schedule_dependence(pdg, dep, map_i);
1193 map_i = isl_map_add_dims(map_i, isl_dim_in, 1);
1194 map_i = isl_map_add_dims(map_i, isl_dim_out, 1);
1195 map_i = isl_map_fix_si(map_i, isl_dim_in, n_in, i);
1196 map_i = isl_map_fix_si(map_i, isl_dim_out, n_out, i);
1197 dep_map = isl_map_union(dep_map, map_i);
1200 return selfloop_size(pdg, dep_map, options->size);
1203 static bool determine_dependence_properties(PDG *pdg, pdg::dependence *dep,
1204 bool evaluate, bool scheduled, struct pn_options *options)
1206 if (dep->type == pdg::dependence::uninitialized) {
1207 fprintf(stderr,
1208 "access to uninitialized data from %s on line %d\n",
1209 dep->array->name->s.c_str(), dep->to->statement->line);
1210 dep->relation->Dump(stderr);
1211 return scheduled;
1213 pdg::IslMap *rel = dep->relation;
1214 if (dep->type == pdg::dependence::pn_part ||
1215 dep->type == pdg::dependence::pn_wire) {
1216 dep->reordering = 0;
1217 dep->multiplicity = 0;
1218 dep->size = new pdg::enumerator(0);
1219 dep->value_size = new integer(0);
1220 return scheduled;
1223 isl_map *dep_map = rel->get_isl_map();
1224 dep_map = isl_map_intersect_params(dep_map, pdg->get_context_isl_set());
1225 dep->reordering = isl_map_is_reordering(dep_map);
1226 dep->multiplicity = 0;
1227 if (!options->reuse)
1228 dep->multiplicity = isl_map_has_multiplicity(dep_map);
1229 if (dep->reordering || dep->multiplicity) {
1230 isl_map_free(dep_map);
1231 return scheduled;
1234 if (dep->to != dep->from && !scheduled) {
1235 schedule(pdg, options);
1236 scheduled = true;
1239 if (dep->to != dep->from)
1240 dep_map = schedule_dependence(pdg, dep, dep_map);
1242 if (!dep->controlled_relation && isl_is_consecutive_loop(dep_map)) {
1243 dep->size = new pdg::enumerator(1);
1244 dep->value_size = new integer(1);
1245 if (dep->from_access == dep->to_access &&
1246 dep->to_access->type != pdg::access::write &&
1247 is_consecutive_dep(pdg, dep, dep_map))
1248 dep->type = pdg::dependence::pn_hold;
1249 } else {
1250 size::enumerator *size = NULL;
1251 if (options->shift_register && dep->to == dep->from &&
1252 !dep->controlled_relation) {
1253 isl_set *ref = dep->to->source->get_isl_set();
1254 size = shift_register_size(pdg, ref,
1255 isl_map_copy(dep_map));
1257 if (size)
1258 dep->type = pdg::dependence::pn_shift;
1259 else
1260 size = compute_size(pdg, dep, dep_map, options);
1261 if (size) {
1262 dep->size = *size;
1263 if (evaluate)
1264 dep->value_size = size->evaluate();
1265 delete size;
1269 isl_map_free(dep_map);
1271 return scheduled;
1274 static void determine_dependence_properties(PDG *pdg, bool evaluate,
1275 bool scheduled, struct pn_options *options)
1277 for (int i = 0; i < pdg->dependences.size(); ++i) {
1278 pdg::dependence *dep = pdg->dependences[i];
1279 scheduled = determine_dependence_properties(pdg, dep, evaluate,
1280 scheduled, options);
1284 /* Can we merge "dep1" and "dep2"?
1286 * That is,
1287 * - do they connect the same from_access to the same to node?
1288 * - is there no reordering in the combined dependence relation?
1290 static bool can_merge(PDG *pdg, pdg::dependence *dep1, pdg::dependence *dep2)
1292 pdg::IslMap *rel1 = dep1->relation;
1293 pdg::IslMap *rel2 = dep2->relation;
1294 isl_map *dep_rel;
1295 bool reordering;
1297 if (dep1->to != dep2->to)
1298 return false;
1299 if (dep1->from_access != dep2->from_access)
1300 return false;
1301 dep_rel = isl_map_union(rel1->get_isl_map(), rel2->get_isl_map());
1302 dep_rel = isl_map_intersect_params(dep_rel, pdg->get_context_isl_set());
1304 reordering = isl_map_is_reordering(dep_rel);
1306 isl_map_free(dep_rel);
1308 return !reordering;
1311 /* Combine the dependences "dep1" and "dep2" into a single pn_union
1312 * dependences with the union dependence relation.
1314 * If "dep2" is already a pn_union, we simply extend it.
1315 * Otherwise, we create a new pn_union modeled after "dep2",
1316 * add it to the list of dependences and turn "dep2" into a pn_part.
1317 * "dep1" is turned into a pn_part in any case.
1319 static void merge_dependences(PDG *pdg, pdg::dependence *dep1,
1320 pdg::dependence *dep2)
1322 pdg::dependence *dep_union;
1324 if (dep2->type == pdg::dependence::pn_union)
1325 dep_union = dep2;
1326 else {
1327 pdg::IslMap *rel;
1328 dep_union = new pdg::dependence;
1329 dep_union->from = dep2->from;
1330 dep_union->to = dep2->to;
1331 dep_union->from_access = dep2->from_access;
1332 dep_union->to_access = NULL;
1333 dep_union->array = dep2->array;
1334 dep_union->type = pdg::dependence::pn_union;
1335 rel = dep2->relation;
1336 dep_union->relation = new pdg::IslMap(rel->get_isl_map());
1337 pdg->dependences.push_back(dep_union);
1339 dep2->type = pdg::dependence::pn_part;
1340 dep2->container = dep_union;
1343 dep1->type = pdg::dependence::pn_part;
1344 dep1->container = dep_union;
1346 dep_union->relation->map = isl_map_union(dep_union->relation->map,
1347 dep1->relation->get_isl_map());
1350 /* Try and merge dependences between a given pair of (distinct) nodes.
1351 * A merge is performed only if it the resulting merged dependence
1352 * does not exhibit any reordering.
1353 * The merging needs to be applied before the buffer size computation
1354 * as the buffer sizes are computed on the merged (pn_union) dependences.
1356 * We run through all original dependences and check whether it can
1357 * be combined with any later dependences. If so, we turn the two
1358 * dependences into "pn_part"s and add an extra pn_union dependence
1359 * that combines the two. The inner loop starts from the latest
1360 * dependence so that we compare with any previously added pn_union
1361 * dependences first. If such a previously add pn_union can be combined
1362 * with the current dependence, it is simply extended to include the
1363 * current dependence.
1365 * We currently don't allow any merging of dependences involving control.
1367 * If the user has turned off merging, the we do nothing.
1368 * We do the same if the user has turned off reuse detection, as there
1369 * may in this case be dependences with multiplicity. It is not clear
1370 * if we would want to merge such edges.
1372 static void merge_dependences(PDG *pdg, struct pn_options *options)
1374 int n_dep;
1376 if (!options->reuse)
1377 return;
1378 if (!options->merge)
1379 return;
1381 n_dep = pdg->dependences.size();
1382 for (int i = 0; i < n_dep; ++i) {
1383 pdg::dependence *dep_i = pdg->dependences[i];
1384 if (dep_i->type != pdg::dependence::flow)
1385 continue;
1386 if (dep_i->to == dep_i->from)
1387 continue;
1388 if (dep_i->controlled_relation)
1389 continue;
1391 for (int j = pdg->dependences.size() - 1; j > i; --j) {
1392 pdg::dependence *dep_j = pdg->dependences[j];
1394 if (dep_j->type != pdg::dependence::flow &&
1395 dep_j->type != pdg::dependence::pn_union)
1396 continue;
1397 if (dep_j->controlled_relation)
1398 continue;
1399 if (!can_merge(pdg, dep_i, dep_j))
1400 continue;
1402 merge_dependences(pdg, dep_i, dep_j);
1407 /* Is "access" one of the filter accesses of "node"?
1409 static bool is_filter_access(pdg::node *node, pdg::access *access)
1411 for (int i = 0; i < node->filters.size(); ++i) {
1412 pdg::call_or_access *coa;
1414 coa = node->filters[i];
1415 assert(coa->type == pdg::call_or_access::t_access);
1416 if (access == coa->access)
1417 return true;
1419 return false;
1422 /* Given the (overapproximation of the) dependence relation "dep_rel",
1423 * check whether "to" and "from" represent the same filter, i.e.,
1424 * whether they refer to the same array element written at the same
1425 * iteration.
1427 * We apply the mappings from source/sink iterations
1428 * to filter access relations to both sides of "dep_rel".
1429 * If the result is a subset of the identity relation, then
1430 * we know that the filter element accessed by the source is
1431 * exactly the same as the filter element accessed by
1432 * the courresponding sink(s).
1434 * If we were unable to find the source for one or both of the two filters,
1435 * then the filter access relations live in different spaces and
1436 * the computed relation cannot be a subset of the identity relation.
1438 static bool is_same_filter(pdg::access *to, pdg::access *from,
1439 __isl_keep isl_map *dep_rel)
1441 isl_union_map *from_access;
1442 isl_union_map *to_access;
1443 isl_union_map *test;
1444 isl_union_map *univ;
1445 isl_union_map *id;
1446 bool same;
1448 if (to->array != from->array)
1449 return false;
1451 from_access = from->extract_access_map();
1452 to_access = to->extract_access_map();
1453 test = isl_union_map_from_map(isl_map_copy(dep_rel));
1454 test = isl_union_map_apply_domain(test, from_access);
1455 test = isl_union_map_apply_range(test, to_access);
1456 univ = isl_union_map_universe(isl_union_map_copy(test));
1457 id = isl_union_set_identity(isl_union_map_domain(univ));
1458 same = isl_union_map_is_subset(test, id);
1459 isl_union_map_free(test);
1460 isl_union_map_free(id);
1462 return same;
1465 /* Insert equalities between source filters and sink filters
1466 * of dependences, whenever we are able to detect that they are the same.
1468 * We first introduce the constraints on the sink filters in the dependence
1469 * relation and we add unconstrained variables for the source filters.
1470 * Then, for each of the sink filters, we check if we can find
1471 * any source filter that has the same value on the other side
1472 * of the dependence. If so, we can keep the constraints on this
1473 * filter value and we add an equality between the source filter
1474 * and the sink filter so that these constraints will also be
1475 * applied to the source filter.
1476 * Otherwise, we eliminate the sink filter value from the constraints.
1478 static void insert_filter_constraints(pdg::dependence *dep)
1480 isl_space *space;
1481 isl_map *map;
1482 isl_map *dep_rel;
1483 int n_in;
1484 int n_out;
1485 bool any = false;
1487 dep_rel = isl_map_copy(dep->relation->map);
1488 n_in = isl_map_dim(dep_rel, isl_dim_in);
1489 n_out = isl_map_dim(dep_rel, isl_dim_out);
1491 space = isl_set_get_space(dep->from->source->set);
1492 map = isl_set_unwrap(isl_set_universe(space));
1493 map = isl_map_reverse(isl_map_domain_map(map));
1494 dep_rel = isl_map_apply_domain(dep_rel, map);
1495 map = isl_set_unwrap(dep->to->source->get_isl_set());
1496 map = isl_map_reverse(isl_map_domain_map(map));
1497 dep_rel = isl_map_apply_range(dep_rel, map);
1499 for (int i = 0; i < dep->to->filters.size(); ++i) {
1500 pdg::call_or_access *coa_i;
1501 pdg::access *access_i;
1502 bool found = false;
1504 coa_i = dep->to->filters[i];
1505 assert(coa_i->type == pdg::call_or_access::t_access);
1506 access_i = coa_i->access;
1508 for (int j = 0; j < dep->from->filters.size(); ++j) {
1509 pdg::call_or_access *coa_j;
1510 pdg::access *access_j;
1512 coa_j = dep->from->filters[j];
1513 assert(coa_j->type == pdg::call_or_access::t_access);
1514 access_j = coa_j->access;
1516 if (!is_same_filter(access_i, access_j,
1517 dep->relation->map))
1518 continue;
1519 dep_rel = isl_map_equate(dep_rel, isl_dim_in, n_in + j,
1520 isl_dim_out, n_out + i);
1521 found = true;
1522 any = true;
1525 if (!found)
1526 dep_rel = isl_map_eliminate(dep_rel, isl_dim_out,
1527 n_out + i, 1);
1530 if (any) {
1531 isl_map_free(dep->relation->map);
1532 dep->relation->map = dep_rel;
1533 } else
1534 isl_map_free(dep_rel);
1537 /* Insert equalities between source filters and sink filters
1538 * of dependences, whenever we are able to detect that they are the same.
1540 * We currently don't introduce any such equalities in dependences
1541 * that involve control variables. Both these control variables and
1542 * the filters will be treated as "dynamic controls" in pn2adg
1543 * and it probably needs to be tweaked to be able to handle two sets
1544 * of dynamic controls.
1546 static void insert_filter_constraints(PDG *pdg)
1548 for (int i = 0; i < pdg->dependences.size(); ++i) {
1549 pdg::dependence *dep = pdg->dependences[i];
1551 if (dep->type == pdg::dependence::uninitialized)
1552 continue;
1553 if (dep->to == dep->from)
1554 continue;
1555 if (dep->controlled_relation)
1556 continue;
1557 if (dep->to->filters.size() == 0)
1558 continue;
1559 if (dep->from->filters.size() == 0)
1560 continue;
1561 if (is_filter_access(dep->to, dep->to_access))
1562 continue;
1563 insert_filter_constraints(dep);
1567 int main(int argc, char * argv[])
1569 isl_ctx *ctx;
1570 FILE *in = stdin, *out = stdout;
1571 int c, ind = 0;
1572 PDG *pdg;
1573 struct pn_options *options = pn_options_new_with_defaults();
1574 bool evaluate = true;
1576 argc = pn_options_parse(options, argc, argv, ISL_ARG_ALL);
1578 if (!options->reuse)
1579 options->propagate = 0;
1581 if (options->input && strcmp(options->input, "-")) {
1582 in = fopen(options->input, "r");
1583 assert(in);
1584 if (!options->output) {
1585 int len = strlen(options->input);
1586 if (len > 5 && !strcmp(options->input+len-5, ".yaml"))
1587 len -= 5;
1588 options->output = (char *)malloc(len+9+1);
1589 strncpy(options->output, options->input, len);
1590 strcpy(options->output+len, options->reuse ? "_pn.yaml" : "_cpn.yaml");
1594 ctx = isl_ctx_alloc_with_options(&pn_options_args, options);
1595 pdg = PDG::Load(in, ctx);
1596 assert(pdg);
1597 int nparam = pdg->params.size();
1599 if (options->propagate)
1600 copy_propagation(pdg);
1602 compute_filter_sources(pdg);
1603 for (int i = 0; i < pdg->arrays.size(); ++i)
1604 find_deps(pdg, pdg->arrays[i], flow);
1605 extract_control_dependences(pdg);
1607 for (int i = 0; i < nparam; ++i)
1608 if (!pdg->params[i]->value) {
1609 evaluate = false;
1610 break;
1613 bool translated;
1614 if (options->reschedule) {
1615 common_dimension(pdg);
1616 translated = false;
1617 } else {
1618 set_schedule_from_prefix(pdg);
1619 translated = true;
1622 detect_reuse(pdg, options);
1623 split_multi_assignment(pdg);
1624 split_wires(pdg);
1625 merge_dependences(pdg, options);
1626 determine_dependence_properties(pdg, evaluate, translated, options);
1627 insert_filter_constraints(pdg);
1629 pdg->add_history_line("pn", argc, argv);
1631 if (options->output && strcmp(options->output, "-")) {
1632 out = fopen(options->output, "w");
1633 assert(out);
1636 pdg->Dump(out);
1637 pdg->free();
1638 delete pdg;
1639 isl_ctx_free(ctx);
1641 return 0;