include/isa/adg.h: directly include required header
[ppn.git] / pn.cc
blobf8c06263145827fb44b9b5ef33607f7308a8a9d9
1 #include <iostream>
2 #include <set>
3 #include <map>
4 #include <vector>
6 #include <isl/flow.h>
8 #include <isa/yaml.h>
9 #include <isa/pdg.h>
10 #include "da.h"
11 #include "size.h"
12 extern "C" {
13 #include "isl_util.h"
15 #include "translation.h"
16 #include "pn_options.h"
18 #include "memrchr.h"
20 using pdg::PDG;
21 using namespace std;
22 using namespace da;
23 using namespace size;
25 /* Check whether node is a propagation node
27 * A propagation node simply copies a value from one array to another array.
28 * In principle, a copy node could also copy a value to the same array,
29 * but then we would have to be careful that the node does not recursively
30 * copy values.
31 * Note that the check is incomplete. If a node performs some additional
32 * operations involving only iterators, then this information is not stored
33 * so we may incorrectly conclude that the node is a copy node.
35 static bool propagation_node(pdg::node *node)
37 pdg::statement *s = node->statement;
38 if (s->accesses.size() != 2)
39 return false;
40 if (s->accesses[0]->type != pdg::access::read)
41 return false;
42 if (s->accesses[1]->type != pdg::access::write)
43 return false;
44 if (s->accesses[0]->array == s->accesses[1]->array)
45 return false;
46 if (s->accesses[1]->array->dims.size() != 0)
47 return false;
48 if (s->top_function && s->top_function->name &&
49 strcmp(s->top_function->name->s.c_str(), ""))
50 return false;
51 return true;
54 static pdg::IslMap *join_input(PDG *pdg, pdg::IslMap *left,
55 pdg::IslMap *right)
57 pdg::IslMap *res;
58 isl_ctx *ctx = pdg->get_isl_ctx();
59 isl_map *rel = left->get_isl_map(ctx);
60 isl_map *acc = right->get_isl_map(ctx);
62 acc = isl_map_apply_domain(acc, rel);
64 res = new pdg::IslMap(acc);
66 return res;
69 /* Given a dependence relation um_rel that maps iterations from
70 * a propagation node to the current node and an access relation
71 * from the current node, drop those iterations from the domain
72 * of the access relation that have been propagated, i.e.,
73 * that are in the range of the dependence relation.
75 * The original access relation is destroyed and a new one
76 * is returned, provided the new access relation is not empty.
77 * If it is empty, then a NULL pointer is returned.
79 * Note that the input access relation may not have been specialized
80 * to the domain of the node, i.e., the access relation may have
81 * a universe domain. In that case, the new relation is unlikely
82 * to be empty, but it may end up having a domain that is disjoint
83 * from the domain of the node.
85 static pdg::IslMap *remove_propagated_from_domain(PDG *pdg,
86 pdg::IslMap *um_rel, pdg::IslMap *um_acc)
88 pdg::IslMap *res = NULL;
89 isl_ctx *ctx = pdg->get_isl_ctx();
90 isl_map *rel = um_rel->get_isl_map(ctx);
91 isl_map *acc = um_acc->get_isl_map(ctx);
93 isl_set *rel_ran = isl_map_range(rel);
94 isl_set *acc_dom = isl_map_domain(isl_map_copy(acc));
96 acc_dom = isl_set_subtract(acc_dom, rel_ran);
97 acc = isl_map_intersect_domain(acc, acc_dom);
99 delete um_acc;
101 if (isl_map_is_empty(acc))
102 isl_map_free(acc);
103 else
104 res = new pdg::IslMap(acc);
106 return res;
109 /* Recursively replace old_access inside call by new_access.
111 static void replace_access(pdg::function_call *call, pdg::access *old_access,
112 pdg::call_or_access *new_coa)
114 for (int i = 0; i < call->arguments.size(); ++i) {
115 pdg::call_or_access *coa = call->arguments[i];
116 if (coa->type == pdg::call_or_access::t_call)
117 replace_access(coa->call, old_access, new_coa);
118 if (coa->type == pdg::call_or_access::t_access &&
119 coa->access == old_access) {
120 *coa = *new_coa;
121 break;
126 /* Replace old_access inside s by new_access.
127 * If empty is not set, then new_access only replaces part of
128 * old_access. This means that old_access is kept in the list
129 * of accesses and that in the parse tree of the statement,
130 * old_access is replaced by a new virtual function call
131 * with old_access and new_access as arguments.
133 static void replace_access(pdg::statement *s, pdg::access *old_access,
134 pdg::access *new_access, bool empty)
136 pdg::call_or_access coa;
138 if (empty)
139 s->accesses.erase(old_access);
140 s->accesses.push_back(new_access);
142 if (!s->top_function)
143 return;
145 if (empty) {
146 coa.type = pdg::call_or_access::t_access;
147 coa.access = new_access;
148 } else {
149 pdg::call_or_access *old_coa, *new_coa;
150 coa.type = pdg::call_or_access::t_call;
151 coa.call = new pdg::function_call;
152 coa.call->name = new str(string("#PHI"));
153 old_coa = new pdg::call_or_access;
154 old_coa->type = pdg::call_or_access::t_access;
155 old_coa->access = old_access;
156 coa.call->arguments.push_back(old_coa);
157 new_coa = new pdg::call_or_access;
158 new_coa->type = pdg::call_or_access::t_access;
159 new_coa->access = new_access;
160 coa.call->arguments.push_back(new_coa);
162 replace_access(s->top_function, old_access, &coa);
165 static void clear_dependences(PDG *pdg)
167 for (int j = 0; j < pdg->dependences.size(); ++j) {
168 pdg::dependence *dep = pdg->dependences[j];
169 delete dep->controlled_relation;
170 delete dep->relation;
171 delete dep;
173 pdg->dependences.resize(0);
176 /* Check if there is any node that simply copies the value from an array
177 * to a scalar. If so, perform dependence analysis on the scalar
178 * and replaces read access to the scalar that depend on writes from
179 * a propagation node to reads from the propagated array.
180 * In particular, the propagated iterations are removed from the access
181 * relation and replaced by an access to the propagated array.
182 * Finally, the propagation node is removed.
184 static void copy_propagation(PDG* pdg)
186 std::set<pdg::node *> to_remove_n;
187 for (int i = 0; i < pdg->nodes.size(); ++i) {
188 pdg::node *node = pdg->nodes[i];
189 pdg::statement *s = node->statement;
190 if (!propagation_node(node))
191 continue;
192 pdg::array *a = s->accesses[1]->array;
193 find_deps(pdg, a, flow);
194 std::set<pdg::access *> to_remove;
195 for (int j = 0; j < pdg->dependences.size(); ++j) {
196 pdg::dependence *dep = pdg->dependences[j];
197 if (dep->controlled_relation)
198 continue;
199 assert(dep->type == pdg::dependence::flow);
200 assert(dep->from != dep->to);
201 if (!propagation_node(dep->from))
202 continue;
203 to_remove_n.insert(dep->from);
204 pdg::IslMap *access_map = dep->from->statement->accesses[0]->map;
205 pdg::IslMap *prop_access = join_input(pdg, dep->relation, access_map);
206 access_map = dep->to_access->map;
207 access_map = remove_propagated_from_domain(pdg, dep->relation,
208 access_map);
209 dep->to_access->map = access_map;
210 bool empty = !access_map;
211 pdg::access *access = new pdg::access;
212 access->nr = dep->to_access->nr;
213 access->array = dep->from->statement->accesses[0]->array;
214 access->type = pdg::access::read;
215 access->map = prop_access;
216 replace_access(dep->to->statement, dep->to_access, access, empty);
217 if (empty)
218 to_remove.insert(dep->to_access);
220 std::set<pdg::access *>::iterator it;
221 for (it = to_remove.begin(); it != to_remove.end(); ++it) {
222 (*it)->array = NULL;
223 (*it)->free();
224 delete (*it);
226 clear_dependences(pdg);
228 if (to_remove_n.size() == 0)
229 return;
230 std::set<pdg::node *>::iterator itn;
231 for (itn = to_remove_n.begin(); itn != to_remove_n.end(); ++itn) {
232 (*itn)->statement->accesses[0]->array = NULL;
233 (*itn)->statement->accesses[1]->array = NULL;
234 (*itn)->free();
235 delete (*itn);
236 pdg->nodes.erase(*itn);
238 for (int i = 0; i < pdg->nodes.size(); ++i)
239 pdg->nodes[i]->nr = i;
242 /* Check whether dep writes and reads from consecutive iterations of
243 * the same domain.
244 * We check this property by testing whether any other read for the
245 * same access occurs in between.
247 bool is_consecutive_dep(PDG *pdg, pdg::dependence *dep, isl_map *map)
249 isl_ctx *ctx = pdg->get_isl_ctx();
250 assert(dep->to == dep->from);
251 for (int i = 0; i < pdg->dependences.size(); ++i) {
252 pdg::dependence *other_dep = pdg->dependences[i];
253 if (other_dep == dep)
254 continue;
255 if (other_dep->to != dep->to)
256 continue;
257 if (other_dep->to_access != dep->to_access)
258 continue;
259 isl_map *other_map = other_dep->relation->get_isl_map(ctx);
260 bool consec = isl_is_consecutive_dep(map, other_map);
261 isl_map_free(other_map);
262 if (!consec)
263 return false;
265 return true;
268 /* An auxiliary class that keeps a reference to an isl_map
269 * and frees it when it goes out of scope.
271 struct temp_map {
272 isl_map * const map;
273 temp_map(isl_map *m) : map(m) {}
274 operator isl_map *() const { return map; }
275 ~temp_map() {
276 isl_map_free(map);
280 /* Set *user to qp of the first call, assuming *user was initialized to NULL.
281 * If this function is called more than once, then return isl_stat_error.
283 static isl_stat extract_single(__isl_take isl_set *set,
284 __isl_take isl_qpolynomial *qp, void *user)
286 isl_qpolynomial **res = (isl_qpolynomial **) user;
288 isl_set_free(set);
290 if (*res) {
291 isl_qpolynomial_free(qp);
292 return isl_stat_error;
295 *res = qp;
296 return isl_stat_ok;
299 /* Check if we can use a shift register for the self-dependence dep
300 * on the domain D.
301 * If yes, return the required size of the shift register.
302 * If no, return NULL.
304 * We assume that the register is shifted on every iteration of D.
305 * If the number of shifts between any pair of writes and reads is
306 * constant, then we can use a shift register.
307 * Note that the size of the shift register may be larger than
308 * that of the FIFO, since there may be iterations of the domain
309 * between corresponding writes and reads where nothing is written
310 * to or read from the shift register.
312 * If "ref" is a wrapped map, then the iteration domain
313 * is in the domain of that map.
315 static size::enumerator *shift_register_size(pdg::PDG *pdg,
316 __isl_take isl_set *ref, __isl_take isl_map *dep)
318 isl_space *dims;
319 isl_set *dep_set;
320 isl_map *read_after_ref;
321 isl_map *write_before_ref;
322 isl_map *ref_between;
323 isl_pw_qpolynomial *pwqp;
324 isl_set *universe;
325 isl_qpolynomial *qp;
326 unsigned dim;
328 if (isl_set_is_wrapping(ref))
329 ref = isl_map_domain(isl_set_unwrap(ref));
331 dim = isl_set_dim(ref, isl_dim_set);
332 dep = isl_map_move_dims(dep, isl_dim_in, dim, isl_dim_out, 0, dim);
333 dep_set = isl_map_domain(dep);
335 read_after_ref = isl_map_lex_ge(isl_set_get_space(ref));
336 read_after_ref = isl_map_insert_dims(read_after_ref, isl_dim_in, 0, dim);
337 write_before_ref = isl_map_lex_lt(isl_set_get_space(ref));
338 write_before_ref = isl_map_add_dims(write_before_ref, isl_dim_in, dim);
339 ref_between = isl_map_intersect(read_after_ref, write_before_ref);
341 ref_between = isl_map_intersect_range(ref_between, ref);
342 ref_between = isl_map_intersect_domain(ref_between,
343 isl_set_copy(dep_set));
345 pwqp = isl_map_card(ref_between);
347 pwqp = isl_pw_qpolynomial_gist(pwqp, dep_set);
349 pwqp = isl_pw_qpolynomial_coalesce(pwqp);
351 qp = NULL;
352 if (isl_pw_qpolynomial_foreach_piece(pwqp, &extract_single, &qp) < 0 ||
353 !qp ||
354 isl_qpolynomial_involves_dims(qp, isl_dim_in, 0, dim + dim)) {
355 isl_qpolynomial_free(qp);
356 isl_pw_qpolynomial_free(pwqp);
357 return NULL;
359 isl_pw_qpolynomial_free(pwqp);
361 qp = isl_qpolynomial_project_domain_on_params(qp);
362 universe = isl_set_universe(isl_qpolynomial_get_domain_space(qp));
363 pwqp = isl_pw_qpolynomial_alloc(universe, qp);
365 return new size::enumerator(pwqp, pdg);
368 /* isl_access_level_before function used in a context where there
369 * is a single iteration domain. The order is given by the order
370 * of the accesses passed through first and second.
371 * If the first access precedes the second, we return 2 * d + 1,
372 * where d is the dimension of the iteration domain, and otherwise 2 * d.
374 static int precedes_access(void *first, void *second)
376 pdg::access *access1 = (pdg::access *) first;
377 pdg::access *access2 = (pdg::access *) second;
378 int d = isl_map_dim(access1->map->map, isl_dim_in);
380 return 2 * d + (access1->nr < access2->nr);
383 /* Return true if all input dimensions are constrained to be equal to the
384 * corresponding output dimensions.
386 static bool is_identity_map(__isl_keep isl_map *map)
388 int is_id;
389 isl_space *space = isl_map_get_space(map);
390 isl_map *id = isl_map_identity(space);
392 is_id = isl_map_is_subset(map, id);
394 isl_map_free(id);
396 return is_id;
399 /* Set buf (of size buf_len) to the prefix of control variables
400 * that correspond to the from and to access of the given "dep"
401 * and return the length of the prefix.
403 static size_t set_local_control_name(char *buf, size_t buf_len,
404 pdg::dependence *dep)
406 snprintf(buf, buf_len, "__last_%s_%d_%s_%d",
407 dep->from->name->s.c_str(), dep->from_access->nr,
408 dep->to->name->s.c_str(), dep->to_access->nr);
409 return strlen(buf);
412 /* Given the name of a binding variable, reset the part that refers
413 * to the sink access by "nr".
415 * The original name is of the form
417 * __last_ND_<source node>_<source access>_ND_<sink node>_<sink access>_*
419 * We simply replace the <sink access> by <nr>.
421 static str *replace_to_access(isl_ctx *ctx, str *id, int nr)
423 const char *name;
424 const char *suffix;
425 const char *infix;
426 char *replaced;
427 size_t len;
428 str *s;
430 name = id->s.c_str();
431 assert(name);
432 suffix = strrchr(name, '_');
433 assert(suffix);
434 infix = (const char *) memrchr(name, '_', suffix - name);
435 assert(infix);
436 len = infix + 1 - name + strlen(suffix) + 20;
437 replaced = isl_alloc_array(ctx, char, len);
438 assert(replaced);
439 len = infix + 1 - name;
440 memcpy(replaced, name, len);
441 snprintf(replaced + len, 20, "%d", nr);
442 len += strlen(replaced + len);
443 strcpy(replaced + len, suffix);
445 s = new str(replaced);
446 free(replaced);
448 return s;
451 /* For each element of controls, replace the part of the name that
452 * refers to the sink access by "nr" and collect the results in
453 * renamed_controls.
455 static void replace_to_access(isl_ctx *ctx, seq<str> &renamed_controls,
456 seq<str> &controls, int nr)
458 for (int i = 0; i < controls.size(); ++i)
459 renamed_controls.push_back(replace_to_access(ctx,
460 controls[i], nr));
463 /* Is the i-th parameter of "map" of the form __last_*
464 * but not of the form local_control*?
466 static bool is_foreign_control(__isl_keep isl_map *map, int i,
467 const char *local_control, size_t len)
469 const char *name;
470 const char *prefix = "__last_";
471 size_t prefix_len = strlen(prefix);
473 if (!isl_map_has_dim_id(map, isl_dim_param, i))
474 return false;
475 name = isl_map_get_dim_name(map, isl_dim_param, i);
476 if (strncmp(name, prefix, prefix_len))
477 return false;
478 return strncmp(name, local_control, len) != 0;
481 /* Remove from "dep" all those parameters that are of the form __last_*
482 * but not of the form local_control* and return the result.
484 static __isl_give isl_map *remove_foreign_controls(__isl_take isl_map *dep,
485 const char *local_control, size_t len)
487 int n_param;
489 n_param = isl_map_dim(dep, isl_dim_param);
490 for (int i = n_param - 1; i >= 0; --i) {
491 if (!is_foreign_control(dep, i, local_control, len))
492 continue;
493 dep = isl_map_project_out(dep, isl_dim_param, i, 1);
495 dep = isl_map_coalesce(dep);
497 return dep;
500 /* Is the i-th parameter of "map" a control, i.e., a parameter
501 * introduced by convert_writer()?
502 * In particular, is the parameter of the form __last_*?
504 static bool is_control(__isl_keep isl_map *map, int i)
506 const char *name;
507 const char *prefix = "__last_";
508 size_t prefix_len = strlen(prefix);
510 if (!isl_map_has_dim_id(map, isl_dim_param, i))
511 return false;
512 name = isl_map_get_dim_name(map, isl_dim_param, i);
513 return strncmp(name, prefix, prefix_len) == 0;
516 /* Remove all parameters that were introduced by convert_writer().
518 static __isl_give isl_map *remove_all_controls(__isl_take isl_map *dep)
520 int n_param;
522 n_param = isl_map_dim(dep, isl_dim_param);
523 for (int i = n_param - 1; i >= 0; --i) {
524 if (!is_control(dep, i))
525 continue;
526 dep = isl_map_project_out(dep, isl_dim_param, i, 1);
528 dep = isl_map_coalesce(dep);
530 return dep;
533 struct add_reuse_data {
534 PDG *pdg;
535 pdg::dependence *dep;
538 extern "C" {
539 static isl_stat add_reuse(__isl_take isl_map *dep_rel, int must,
540 void *dep_user, void *user);
543 /* Add a reuse dependence with dependence relation "dep_rel" to
544 * data->pdg->dependences.
545 * data->dep corresponds to the original dependence that is reusing
546 * some value that was previously used by "propagate_access", from
547 * the same node.
548 * Since "dep_rel" was obtained from a relation with local
549 * control variables, we need to remove them to obtain the
550 * dependence relation on the reuse dependence.
552 * If we are reusing control variables, then we need to rename
553 * the from_control to refer to the access where we are reusing
554 * the control variables from.
556 * If the dependence relations maps iterations to themselves, then
557 * we mark the new reuse dependence as a wire.
559 static isl_stat add_reuse(__isl_take isl_map *dep_rel, int must, void *dep_user,
560 void *user)
562 pdg::access *propagate_access = (pdg::access *) dep_user;
563 add_reuse_data *data = (add_reuse_data *) user;
564 pdg::dependence *reuse_dep;
565 isl_ctx *ctx = isl_map_get_ctx(dep_rel);
567 reuse_dep = new pdg::dependence;
568 reuse_dep->array = data->dep->array;
569 replace_to_access(ctx, reuse_dep->from_controls,
570 data->dep->from_controls, propagate_access->nr);
571 reuse_dep->to_controls = data->dep->to_controls;
572 reuse_dep->from = data->dep->to;
573 reuse_dep->to = data->dep->to;
574 reuse_dep->from_access = propagate_access;
575 reuse_dep->to_access = data->dep->to_access;
576 if (reuse_dep->from == reuse_dep->to && is_identity_map(dep_rel))
577 reuse_dep->type = pdg::dependence::pn_wire;
578 else
579 reuse_dep->type = data->dep->type;
580 if (data->dep->controlled_relation) {
581 pdg::IslMap *cr = data->dep->controlled_relation;
582 isl_set *dom = isl_map_range(cr->get_isl_map());
583 isl_map *control_rel = isl_map_copy(dep_rel);
584 control_rel = isl_map_intersect_range(control_rel, dom);
585 reuse_dep->controlled_relation = new pdg::IslMap(control_rel);
587 dep_rel = remove_all_controls(dep_rel);
588 reuse_dep->relation = new pdg::IslMap(dep_rel);
589 data->pdg->dependences.push_back(reuse_dep);
591 return isl_stat_ok;
594 /* Detect reuse among the dependences in "deps", adding split off
595 * dependences to pdg->dependences.
596 * Each of the dependences in "deps" originates from the same
597 * write access and ends in the same node.
599 * We look for values, i.e., iterations of the write access,
600 * that are used several times. To do so, we perform dependence
601 * analysis on the inverted dependence relations. That is,
602 * we use these inverted dependence relations as "access relations",
603 * accessing iterations of the write access.
604 * We consider each dependence in turn as a "read", each time taking
605 * all dependences as writes.
606 * In the result of such a dependence analysis, the "uninitialized reads"
607 * correspond to the first use of a result from the original write access,
608 * while all the "dependences" corespond to a propagation of a value
609 * from one original read access to another original read access.
611 * If the dependence has a controlled_relation, then we use this
612 * controlled_relation as the "access relation" after removing all
613 * the foreign controls. This ensures that we only reuse data if
614 * the last iteration hasn't changed.
615 * After restricting the range of the controlled_relation based on
616 * the "uninitialized reads", we recompute the uncontrolled relation
617 * from this result.
619 * If there is only one dependence in "deps" and if that dependence
620 * is single-valued, then obviously there can be no reuse, so we skip
621 * the analysis.
623 * We currently assume that none of the accesses has an extended_relation.
625 static void detect_reuse(PDG *pdg, std::vector<pdg::dependence *> &deps)
627 add_reuse_data data = { pdg };
628 char buf[120];
629 size_t len;
631 if (deps.size() == 1 &&
632 isl_map_is_single_valued(deps[0]->relation->map))
633 return;
635 for (int i = 0; i < deps.size(); ++i) {
636 isl_access_info *ai;
637 isl_flow *flow;
638 isl_set *first;
639 isl_map *local;
640 pdg::IslMap *rel;
642 assert(!deps[i]->extended_relation);
644 if (deps[i]->controlled_relation) {
645 local = deps[i]->controlled_relation->get_isl_map();
646 len = set_local_control_name(buf, sizeof(buf), deps[i]);
647 local = remove_foreign_controls(local, buf, len);
648 } else
649 local = deps[i]->relation->get_isl_map();
650 local = isl_map_reverse(local);
652 data.dep = deps[i];
653 ai = isl_access_info_alloc(isl_map_copy(local),
654 deps[i]->to_access, &precedes_access, deps.size());
655 for (int j = 0; j < deps.size(); ++j) {
656 isl_map *map;
657 if (i == j) {
658 map = isl_map_copy(local);
659 } else {
660 map = deps[j]->relation->get_isl_map();
661 map = isl_map_reverse(map);
663 ai = isl_access_info_add_source(ai, map,
664 1, deps[j]->to_access);
666 flow = isl_access_info_compute_flow(ai);
667 isl_flow_foreach(flow, &add_reuse, &data);
668 first = isl_map_domain(isl_flow_get_no_source(flow, 1));
669 isl_flow_free(flow);
671 rel = deps[i]->relation;
672 if (deps[i]->controlled_relation) {
673 pdg::IslMap *cr = deps[i]->controlled_relation;
674 cr->map = isl_map_intersect_range(cr->map, first);
675 isl_map_free(rel->map);
676 rel->map = remove_all_controls(isl_map_copy(cr->map));
677 } else
678 rel->map = isl_map_intersect_range(rel->map, first);
680 isl_map_free(local);
684 /* Has this dependence been created during the detection
685 * of multiple assignments? In particular, does this dependence
686 * propagate the values in the source.
688 static bool is_multi_assignment_propagation(pdg::dependence *dep)
690 return dep->to_access == dep->from_access &&
691 dep->to_access->type == pdg::access::write;
694 typedef std::pair<pdg::access *, pdg::node *> an_pair;
695 typedef std::pair<int, an_pair> nan_triple;
697 struct nan_triple_cmp {
698 bool operator()(nan_triple t1, nan_triple t2) const {
699 if (t1.first != t2.first)
700 return t1.first < t2.first;
701 if (t1.second.first->nr != t2.second.first->nr)
702 return t1.second.first->nr < t2.second.first->nr;
703 return t1.second.second->nr < t2.second.second->nr;
707 typedef std::map<nan_triple, std::vector<pdg::dependence *>, nan_triple_cmp>
708 nan2deps;
710 /* Detect reuse of the same value (originating from the same
711 * write access) within a node and split the corresponding dependence
712 * into part of the original dependences that use the value for
713 * the first time and internal dependences that propagate the value.
715 * If a scheduling is applied that changes the order of the iterations
716 * within a given node, then this scheduling should be performed
717 * before the reuse detection.
719 * We first collect the dependences that originate in a given access
720 * and end up in a given node and then process each such collection
721 * in turn, in an order that does not depend on pointer values.
722 * While collecting dependences, we skip those that correspond
723 * to the propagation of multiple assignments to the next potential
724 * assignment.
726 * Dependences that propagate data (those that have a dep->array)
727 * are treated separately from those that propagate control.
729 * If the user has turned off reuse detection, then we do nothing.
731 static void detect_reuse(PDG *pdg, struct pn_options *options)
733 nan2deps access_deps;
734 nan2deps control_deps;
735 nan2deps::iterator it;
737 if (!options->reuse)
738 return;
740 for (int i = 0; i < pdg->dependences.size(); ++i) {
741 pdg::dependence *dep = pdg->dependences[i];
742 if (dep->type == pdg::dependence::uninitialized)
743 continue;
744 if (is_multi_assignment_propagation(dep))
745 continue;
746 an_pair p(dep->from_access, dep->to);
747 nan_triple t(dep->from->nr, p);
748 if (dep->array)
749 access_deps[t].push_back(dep);
750 else
751 control_deps[t].push_back(dep);
754 for (it = access_deps.begin(); it != access_deps.end(); ++it)
755 detect_reuse(pdg, it->second);
756 for (it = control_deps.begin(); it != control_deps.end(); ++it)
757 detect_reuse(pdg, it->second);
760 /* isl_access_level_before function used in a context where the
761 * iteration domains live in a common space. We therefore just
762 * need to retun 2 * the dimension of this space, which is stored
763 * in *first (and *second).
765 static int common_space(void *first, void *second)
767 int depth = *(int *) first;
768 return 2 * depth;
771 /* Assign dep to *user. This function is expected to be called
772 * exactly once.
774 static isl_stat extract_dep(__isl_take isl_map *dep, int must,
775 void *dep_user, void *user)
777 isl_map **map_p = (isl_map **) user;
779 *map_p = dep;
781 return isl_stat_ok;
784 /* Is the i-th parameter of "set" of the form __last_*
785 * but not of the form local_control*?
787 static bool is_foreign_control(__isl_keep isl_set *set, int i,
788 const char *local_control, size_t len)
790 const char *name;
791 const char *prefix = "__last_";
792 size_t prefix_len = strlen(prefix);
794 if (!isl_set_has_dim_id(set, isl_dim_param, i))
795 return false;
796 name = isl_set_get_dim_name(set, isl_dim_param, i);
797 if (strncmp(name, prefix, prefix_len))
798 return false;
799 return strncmp(name, local_control, len) != 0;
802 /* Does "set" have any parameters of the form __last_*
803 * that are not of the form local_control*?
805 static __isl_give isl_set *remove_foreign_controls(__isl_take isl_set *set,
806 const char *local_control, size_t len)
808 int n_param;
810 n_param = isl_set_dim(set, isl_dim_param);
811 for (int i = n_param - 1; i >= 0; --i) {
812 if (!is_foreign_control(set, i, local_control, len))
813 continue;
814 set = isl_set_project_out(set, isl_dim_param, i, 1);
816 set = isl_set_coalesce(set);
818 return set;
821 /* Given a dependence such that the dependence relation
822 * is not injective, split the dependence into two parts,
823 * one that propagates the value from a potential source iteration
824 * to the next potential source iteration and one that sends
825 * the data from the final potential source iteration to the sink
826 * iteration.
828 * The dependence may either be a control dependence, propagating
829 * control variables, or a data dependence, in which case it has
830 * a controlled_relation and it is the uncontrolled relation that
831 * is not injective.
833 * To obtain the last potential source iteration, we simply
834 * compute the lexicographic maximum of all potential source iterations.
836 * To obtain the dependence from one potential source iteration
837 * to the next potential source iteration, we apply
838 * dependence analysis on the dependence relation.
839 * In particular, we need a mapping from source iterations to
840 * the next source iteration associated to the same sink iteration,
841 * so we simply treat the original dependence relation as an access relation.
843 * The mapping to the next potential source should not have any controls.
844 * If the input dependence is a control dependence, then it is propagating
845 * control variables itself. If it is a data dependence, then we want
846 * to propagate values to the next potential source independently of
847 * any control.
849 * The constraints on the controls for the dependence from the final
850 * potential source iteration should be the same as those on the
851 * original relation, when seen from the destination node.
853 * We currently assume that there is no extended relation associated
854 * to the dependence.
856 static void split_multi_assignment(PDG *pdg, pdg::dependence *dep)
858 isl_set *dom;
859 isl_map *last;
860 isl_map *next = NULL;
861 isl_access_info *ai;
862 isl_flow *flow;
863 int depth;
864 pdg::dependence *next_dep;
865 char buf[120];
866 size_t len;
868 assert(!dep->extended_relation);
870 len = set_local_control_name(buf, sizeof(buf), dep);
872 depth = isl_map_dim(dep->relation->map, isl_dim_in);
873 ai = isl_access_info_alloc(isl_map_copy(dep->relation->map),
874 &depth, &common_space, 1);
875 ai = isl_access_info_add_source(ai, isl_map_copy(dep->relation->map),
876 1, &depth);
877 flow = isl_access_info_compute_flow(ai);
878 isl_flow_foreach(flow, &extract_dep, &next);
879 isl_flow_free(flow);
881 last = isl_map_copy(dep->relation->map);
882 last = isl_map_reverse(isl_map_lexmax(isl_map_reverse(last)));
884 next_dep = new pdg::dependence;
885 next_dep->array = dep->array;
886 next_dep->from_controls = dep->from_controls;
887 next_dep->to_controls = dep->to_controls;
888 next_dep->type = dep->type;
889 next_dep->from = dep->from;
890 next_dep->to = dep->from;
891 next_dep->from_access = dep->from_access;
892 next_dep->to_access = dep->from_access;
893 next_dep->relation = new pdg::IslMap(next);
894 pdg->dependences.push_back(next_dep);
896 dep->relation->map = isl_map_intersect(dep->relation->map, last);
897 if (dep->controlled_relation)
898 dep->controlled_relation->map =
899 isl_map_intersect_range(isl_map_copy(dep->relation->map),
900 isl_map_range(dep->controlled_relation->map));
903 /* If any sink iteration has more than one potential source
904 * iteration, we split off the propagation of the data on the from
905 * node from the transfer of the data to the to node.
907 * We only perform this operation here on (data) dependences
908 * with a "controlled_relation". The corresponding control dependence
909 * has already been handled from within extract_control_dependence.
910 * Other data dependences have an exact dependence relation and
911 * can therefore not exhibit multiple assignments.
913 static void split_multi_assignment(PDG *pdg)
915 for (int i = 0; i < pdg->dependences.size(); ++i) {
916 pdg::dependence *dep = pdg->dependences[i];
917 if (!dep->controlled_relation)
918 continue;
919 if (isl_map_is_injective(dep->relation->map))
920 continue;
921 split_multi_assignment(pdg, dep);
925 /* Does "dep" have any parameters of the form __last_*?
927 static bool has_controls(__isl_keep isl_map *dep)
929 int n_param;
930 const char *prefix = "__last_";
931 size_t prefix_len = strlen(prefix);
933 n_param = isl_map_dim(dep, isl_dim_param);
934 for (int i = 0; i < n_param; ++i) {
935 const char *name;
937 if (!isl_map_has_dim_id(dep, isl_dim_param, i))
938 continue;
939 name = isl_map_get_dim_name(dep, isl_dim_param, i);
940 if (!strncmp(name, prefix, prefix_len))
941 return true;
944 return false;
947 /* Is the i-th parameter of "map" of the form local_control*?
948 * "len" is the length of "local_control".
950 static bool is_local_control(__isl_keep isl_map *map, int i,
951 const char *local_control, size_t len)
953 const char *name;
955 if (!isl_map_has_dim_id(map, isl_dim_param, i))
956 return false;
957 name = isl_map_get_dim_name(map, isl_dim_param, i);
958 return strncmp(name, local_control, len) == 0;
961 /* Does "dep" have any parameters of the form __last_*
962 * that are not of the form local_control*?
964 static bool has_foreign_controls(__isl_keep isl_map *dep,
965 const char *local_control, size_t len)
967 int n_param;
969 n_param = isl_map_dim(dep, isl_dim_param);
970 for (int i = 0; i < n_param; ++i)
971 if (is_foreign_control(dep, i, local_control, len))
972 return true;
974 return false;
977 /* Does "dep" have any parameters of the form local_control*?
978 * "len" is the length of "local_control".
980 static bool has_local_controls(__isl_keep isl_map *dep,
981 const char *local_control, size_t len)
983 int n_param;
985 n_param = isl_map_dim(dep, isl_dim_param);
986 for (int i = 0; i < n_param; ++i)
987 if (is_local_control(dep, i, local_control, len))
988 return true;
990 return false;
993 /* Extract a control dependence from a dependence with a controlled_relation.
994 * The control dependence transfers the values of the control variables
995 * that correspond to the given dependence, i.e., those that correspond
996 * to the from and to access of the dependence.
997 * We therefore don't need to do anything if the controlled_relation
998 * only involves foreign controls.
1000 * from_controls and to_controls are set from the local control variables
1001 * in dep->controlled_relation.
1003 * The uncontrolled dependence relation may not be injective,
1004 * in which case the initial dependence relation on the control
1005 * dependence is also non-injective. In such cases, the control
1006 * dependence is split using split_multi_assignment in two parts,
1007 * one that propagate the current value of the controls to the next
1008 * iteration of the source and one that sends the final values to the sink.
1009 * The data dependence is split later on.
1011 static void extract_control_dependence(PDG *pdg, pdg::dependence *dep)
1013 pdg::dependence *control;
1014 char buf[120];
1015 size_t len;
1016 int n_param;
1017 isl_map *rel;
1019 len = set_local_control_name(buf, sizeof(buf), dep);
1020 rel = dep->controlled_relation->map;
1021 if (!has_local_controls(rel, buf, len))
1022 return;
1023 n_param = isl_map_dim(rel, isl_dim_param);
1025 control = new pdg::dependence;
1026 control->type = dep->type;
1027 control->from = dep->from;
1028 control->to = dep->to;
1029 control->from_access = dep->from_access;
1030 control->to_access = dep->to_access;
1031 control->relation = new pdg::IslMap(dep->relation->get_isl_map());
1032 for (int i = 0; i < n_param; ++i) {
1033 const char *name;
1034 if (!isl_map_has_dim_id(rel, isl_dim_param, i))
1035 continue;
1036 name = isl_map_get_dim_name(rel, isl_dim_param, i);
1037 if (strncmp(name, buf, len) != 0)
1038 continue;
1039 control->from_controls.push_back(new str(name));
1040 control->to_controls.push_back(new str(name));
1042 pdg->dependences.push_back(control);
1044 if (isl_map_is_injective(control->relation->map))
1045 return;
1046 split_multi_assignment(pdg, control);
1049 /* Extract a control dependence from each dependence with a controlled_relation.
1051 static void extract_control_dependences(PDG *pdg)
1053 int n_dep = pdg->dependences.size();
1055 for (int i = 0; i < n_dep; ++i) {
1056 pdg::dependence *dep = pdg->dependences[i];
1057 if (!dep->controlled_relation)
1058 continue;
1059 extract_control_dependence(pdg, dep);
1063 /* Split off the communication of data, along with the corresponding
1064 * controls, from selecting the data based on other controls.
1065 * "dep" is modified to only refer to the controls that correspond
1066 * to the given from and to access and an extra wire is introduced
1067 * to select the data.
1068 * If "dep" corresponds to a propagation from one potential source
1069 * to the next potential source, then it already only refers to
1070 * "local" controls. We handle this case separately so that we
1071 * don't have to add a special case to set_local_control_name
1072 * for setting up the right name for local controls on such dependences.
1074 * A new virtual access is created to act as the target of the modified
1075 * communication dependence and the source of the selection dependence.
1076 * If the input "dep" did not refer to the corresponding controls,
1077 * then the output "dep" does not refer to any control and
1078 * controlled_relation is cleared.
1080 static void split_wire(PDG *pdg, pdg::dependence *dep)
1082 isl_space *space;
1083 isl_set *dom;
1084 isl_map *rel;
1085 isl_map *id;
1086 pdg::dependence *wire;
1087 pdg::access *access;
1088 char buf[120];
1089 size_t len;
1091 if (is_multi_assignment_propagation(dep))
1092 return;
1094 assert(!dep->extended_relation);
1096 rel = dep->controlled_relation->map;
1097 len = set_local_control_name(buf, sizeof(buf), dep);
1099 if (!has_foreign_controls(rel, buf, len))
1100 return;
1102 space = isl_map_get_space(dep->controlled_relation->map);
1103 space = isl_space_range(space);
1104 space = isl_space_map_from_set(space);
1105 id = isl_map_identity(space);
1106 dom = isl_map_range(isl_map_copy(dep->controlled_relation->map));
1107 id = isl_map_intersect_domain(id, dom);
1109 access = new pdg::access;
1110 access->array = dep->to_access->array;
1111 access->nr = dep->to->statement->accesses.size();
1112 dep->to->statement->accesses.push_back(access);
1114 wire = new pdg::dependence;
1115 wire->array = dep->array;
1116 wire->type = pdg::dependence::pn_wire;
1117 wire->from = dep->to;
1118 wire->to = dep->to;
1119 wire->from_access = access;
1120 wire->to_access = dep->to_access;
1121 wire->relation = new pdg::IslMap(id);
1122 pdg->dependences.push_back(wire);
1124 dep->to_access = access;
1125 dep->controlled_relation->map = remove_foreign_controls(rel, buf, len);
1126 if (!has_controls(dep->controlled_relation->map)) {
1127 delete dep->controlled_relation;
1128 dep->controlled_relation = NULL;
1132 /* If the dependence involves "foreign" controls, i.e., controls
1133 * that correspond to other dependences, then we split off
1134 * the communication of the data (along with the "local" controls)
1135 * from the selection of the data based on the foreign controls.
1137 static void split_wires(PDG *pdg)
1139 for (int i = 0; i < pdg->dependences.size(); ++i) {
1140 pdg::dependence *dep = pdg->dependences[i];
1141 if (!dep->controlled_relation)
1142 continue;
1143 split_wire(pdg, dep);
1147 static void schedule(PDG *pdg, struct pn_options *options)
1149 translate(pdg, options->move);
1152 /* Compute the size of the dependence "dep" with scheduled dependence
1153 * relation "dep_map".
1155 * If "dep" is of type pn_union, then it may contains parts that read
1156 * from the channel in the same iteration. We therefore need to recombine
1157 * the dependence relations of those parts, but separate them apart.
1158 * In particular, we add an extra inner dimension with a fixed value
1159 * corresponding to the index of the dependence.
1161 static size::enumerator *compute_size(pdg::PDG *pdg, pdg::dependence *dep,
1162 __isl_take isl_map *dep_map, pn_options *options)
1164 dep_map = isl_map_copy(dep_map);
1165 if (dep->type == pdg::dependence::pn_union) {
1166 isl_space *space = isl_map_get_space(dep_map);
1167 int n_in, n_out;
1169 n_in = isl_space_dim(space, isl_dim_in);
1170 n_out = isl_space_dim(space, isl_dim_out);
1171 space = isl_space_add_dims(space, isl_dim_in, 1);
1172 space = isl_space_add_dims(space, isl_dim_out, 1);
1173 isl_map_free(dep_map);
1174 dep_map = isl_map_empty(space);
1175 for (int i = 0; i < pdg->dependences.size(); ++i) {
1176 pdg::dependence *part = pdg->dependences[i];
1177 isl_map *map_i;
1179 if (part->type != pdg::dependence::pn_part)
1180 continue;
1181 if (part->container != dep)
1182 continue;
1183 map_i = part->relation->get_isl_map();
1184 map_i = isl_map_intersect_params(map_i,
1185 pdg->get_context_isl_set());
1186 map_i = schedule_dependence(pdg, dep, map_i);
1187 map_i = isl_map_add_dims(map_i, isl_dim_in, 1);
1188 map_i = isl_map_add_dims(map_i, isl_dim_out, 1);
1189 map_i = isl_map_fix_si(map_i, isl_dim_in, n_in, i);
1190 map_i = isl_map_fix_si(map_i, isl_dim_out, n_out, i);
1191 dep_map = isl_map_union(dep_map, map_i);
1194 return selfloop_size(pdg, dep_map, options->size);
1197 static bool determine_dependence_properties(PDG *pdg, pdg::dependence *dep,
1198 bool evaluate, bool scheduled, struct pn_options *options)
1200 if (dep->type == pdg::dependence::uninitialized) {
1201 fprintf(stderr,
1202 "access to uninitialized data from %s on line %d\n",
1203 dep->array->name->s.c_str(), dep->to->statement->line);
1204 dep->relation->Dump(stderr);
1205 return scheduled;
1207 pdg::IslMap *rel = dep->relation;
1208 if (dep->type == pdg::dependence::pn_part ||
1209 dep->type == pdg::dependence::pn_wire) {
1210 dep->reordering = 0;
1211 dep->multiplicity = 0;
1212 dep->size = new pdg::enumerator(0);
1213 dep->value_size = new integer(0);
1214 return scheduled;
1217 isl_map *dep_map = rel->get_isl_map();
1218 dep_map = isl_map_intersect_params(dep_map, pdg->get_context_isl_set());
1219 dep->reordering = isl_map_is_reordering(dep_map);
1220 dep->multiplicity = 0;
1221 if (!options->reuse)
1222 dep->multiplicity = isl_map_has_multiplicity(dep_map);
1223 if (dep->reordering || dep->multiplicity) {
1224 isl_map_free(dep_map);
1225 return scheduled;
1228 if (dep->to != dep->from && !scheduled) {
1229 schedule(pdg, options);
1230 scheduled = true;
1233 if (dep->to != dep->from)
1234 dep_map = schedule_dependence(pdg, dep, dep_map);
1236 if (!dep->controlled_relation && isl_is_consecutive_loop(dep_map)) {
1237 dep->size = new pdg::enumerator(1);
1238 dep->value_size = new integer(1);
1239 if (dep->from_access == dep->to_access &&
1240 dep->to_access->type != pdg::access::write &&
1241 is_consecutive_dep(pdg, dep, dep_map))
1242 dep->type = pdg::dependence::pn_hold;
1243 } else {
1244 size::enumerator *size = NULL;
1245 if (options->shift_register && dep->to == dep->from &&
1246 !dep->controlled_relation) {
1247 isl_set *ref = dep->to->source->get_isl_set();
1248 size = shift_register_size(pdg, ref,
1249 isl_map_copy(dep_map));
1251 if (size)
1252 dep->type = pdg::dependence::pn_shift;
1253 else
1254 size = compute_size(pdg, dep, dep_map, options);
1255 if (size) {
1256 dep->size = *size;
1257 if (evaluate)
1258 dep->value_size = size->evaluate();
1259 delete size;
1263 isl_map_free(dep_map);
1265 return scheduled;
1268 static void determine_dependence_properties(PDG *pdg, bool evaluate,
1269 bool scheduled, struct pn_options *options)
1271 for (int i = 0; i < pdg->dependences.size(); ++i) {
1272 pdg::dependence *dep = pdg->dependences[i];
1273 scheduled = determine_dependence_properties(pdg, dep, evaluate,
1274 scheduled, options);
1278 /* Can we merge "dep1" and "dep2"?
1280 * That is,
1281 * - do they connect the same from_access to the same to node?
1282 * - is there no reordering in the combined dependence relation?
1284 static bool can_merge(PDG *pdg, pdg::dependence *dep1, pdg::dependence *dep2)
1286 pdg::IslMap *rel1 = dep1->relation;
1287 pdg::IslMap *rel2 = dep2->relation;
1288 isl_map *dep_rel;
1289 bool reordering;
1291 if (dep1->to != dep2->to)
1292 return false;
1293 if (dep1->from_access != dep2->from_access)
1294 return false;
1295 dep_rel = isl_map_union(rel1->get_isl_map(), rel2->get_isl_map());
1296 dep_rel = isl_map_intersect_params(dep_rel, pdg->get_context_isl_set());
1298 reordering = isl_map_is_reordering(dep_rel);
1300 isl_map_free(dep_rel);
1302 return !reordering;
1305 /* Combine the dependences "dep1" and "dep2" into a single pn_union
1306 * dependences with the union dependence relation.
1308 * If "dep2" is already a pn_union, we simply extend it.
1309 * Otherwise, we create a new pn_union modeled after "dep2",
1310 * add it to the list of dependences and turn "dep2" into a pn_part.
1311 * "dep1" is turned into a pn_part in any case.
1313 static void merge_dependences(PDG *pdg, pdg::dependence *dep1,
1314 pdg::dependence *dep2)
1316 pdg::dependence *dep_union;
1318 if (dep2->type == pdg::dependence::pn_union)
1319 dep_union = dep2;
1320 else {
1321 pdg::IslMap *rel;
1322 dep_union = new pdg::dependence;
1323 dep_union->from = dep2->from;
1324 dep_union->to = dep2->to;
1325 dep_union->from_access = dep2->from_access;
1326 dep_union->to_access = NULL;
1327 dep_union->array = dep2->array;
1328 dep_union->type = pdg::dependence::pn_union;
1329 rel = dep2->relation;
1330 dep_union->relation = new pdg::IslMap(rel->get_isl_map());
1331 pdg->dependences.push_back(dep_union);
1333 dep2->type = pdg::dependence::pn_part;
1334 dep2->container = dep_union;
1337 dep1->type = pdg::dependence::pn_part;
1338 dep1->container = dep_union;
1340 dep_union->relation->map = isl_map_union(dep_union->relation->map,
1341 dep1->relation->get_isl_map());
1344 /* Try and merge dependences between a given pair of (distinct) nodes.
1345 * A merge is performed only if it the resulting merged dependence
1346 * does not exhibit any reordering.
1347 * The merging needs to be applied before the buffer size computation
1348 * as the buffer sizes are computed on the merged (pn_union) dependences.
1350 * We run through all original dependences and check whether it can
1351 * be combined with any later dependences. If so, we turn the two
1352 * dependences into "pn_part"s and add an extra pn_union dependence
1353 * that combines the two. The inner loop starts from the latest
1354 * dependence so that we compare with any previously added pn_union
1355 * dependences first. If such a previously add pn_union can be combined
1356 * with the current dependence, it is simply extended to include the
1357 * current dependence.
1359 * We currently don't allow any merging of dependences involving control.
1361 * If the user has turned off merging, the we do nothing.
1362 * We do the same if the user has turned off reuse detection, as there
1363 * may in this case be dependences with multiplicity. It is not clear
1364 * if we would want to merge such edges.
1366 static void merge_dependences(PDG *pdg, struct pn_options *options)
1368 int n_dep;
1370 if (!options->reuse)
1371 return;
1372 if (!options->merge)
1373 return;
1375 n_dep = pdg->dependences.size();
1376 for (int i = 0; i < n_dep; ++i) {
1377 pdg::dependence *dep_i = pdg->dependences[i];
1378 if (dep_i->type != pdg::dependence::flow)
1379 continue;
1380 if (dep_i->to == dep_i->from)
1381 continue;
1382 if (dep_i->controlled_relation)
1383 continue;
1385 for (int j = pdg->dependences.size() - 1; j > i; --j) {
1386 pdg::dependence *dep_j = pdg->dependences[j];
1388 if (dep_j->type != pdg::dependence::flow &&
1389 dep_j->type != pdg::dependence::pn_union)
1390 continue;
1391 if (dep_j->controlled_relation)
1392 continue;
1393 if (!can_merge(pdg, dep_i, dep_j))
1394 continue;
1396 merge_dependences(pdg, dep_i, dep_j);
1401 /* Is "access" one of the filter accesses of "node"?
1403 static bool is_filter_access(pdg::node *node, pdg::access *access)
1405 for (int i = 0; i < node->filters.size(); ++i) {
1406 pdg::call_or_access *coa;
1408 coa = node->filters[i];
1409 assert(coa->type == pdg::call_or_access::t_access);
1410 if (access == coa->access)
1411 return true;
1413 return false;
1416 /* Given the (overapproximation of the) dependence relation "dep_rel",
1417 * check whether "to" and "from" represent the same filter, i.e.,
1418 * whether they refer to the same array element written at the same
1419 * iteration.
1421 * We apply the mappings from source/sink iterations
1422 * to filter access relations to both sides of "dep_rel".
1423 * If the result is a subset of the identity relation, then
1424 * we know that the filter element accessed by the source is
1425 * exactly the same as the filter element accessed by
1426 * the courresponding sink(s).
1428 * If we were unable to find the source for one or both of the two filters,
1429 * then the filter access relations live in different spaces and
1430 * the computed relation cannot be a subset of the identity relation.
1432 static bool is_same_filter(pdg::access *to, pdg::access *from,
1433 __isl_keep isl_map *dep_rel)
1435 isl_union_map *from_access;
1436 isl_union_map *to_access;
1437 isl_union_map *test;
1438 isl_union_map *univ;
1439 isl_union_map *id;
1440 bool same;
1442 if (to->array != from->array)
1443 return false;
1445 from_access = from->extract_access_map();
1446 to_access = to->extract_access_map();
1447 test = isl_union_map_from_map(isl_map_copy(dep_rel));
1448 test = isl_union_map_apply_domain(test, from_access);
1449 test = isl_union_map_apply_range(test, to_access);
1450 univ = isl_union_map_universe(isl_union_map_copy(test));
1451 id = isl_union_set_identity(isl_union_map_domain(univ));
1452 same = isl_union_map_is_subset(test, id);
1453 isl_union_map_free(test);
1454 isl_union_map_free(id);
1456 return same;
1459 /* Insert equalities between source filters and sink filters
1460 * of dependences, whenever we are able to detect that they are the same.
1462 * We first introduce the constraints on the sink filters in the dependence
1463 * relation and we add unconstrained variables for the source filters.
1464 * Then, for each of the sink filters, we check if we can find
1465 * any source filter that has the same value on the other side
1466 * of the dependence. If so, we can keep the constraints on this
1467 * filter value and we add an equality between the source filter
1468 * and the sink filter so that these constraints will also be
1469 * applied to the source filter.
1470 * Otherwise, we eliminate the sink filter value from the constraints.
1472 static void insert_filter_constraints(pdg::dependence *dep)
1474 isl_space *space;
1475 isl_map *map;
1476 isl_map *dep_rel;
1477 int n_in;
1478 int n_out;
1479 bool any = false;
1481 dep_rel = isl_map_copy(dep->relation->map);
1482 n_in = isl_map_dim(dep_rel, isl_dim_in);
1483 n_out = isl_map_dim(dep_rel, isl_dim_out);
1485 space = isl_set_get_space(dep->from->source->set);
1486 map = isl_set_unwrap(isl_set_universe(space));
1487 map = isl_map_reverse(isl_map_domain_map(map));
1488 dep_rel = isl_map_apply_domain(dep_rel, map);
1489 map = isl_set_unwrap(dep->to->source->get_isl_set());
1490 map = isl_map_reverse(isl_map_domain_map(map));
1491 dep_rel = isl_map_apply_range(dep_rel, map);
1493 for (int i = 0; i < dep->to->filters.size(); ++i) {
1494 pdg::call_or_access *coa_i;
1495 pdg::access *access_i;
1496 bool found = false;
1498 coa_i = dep->to->filters[i];
1499 assert(coa_i->type == pdg::call_or_access::t_access);
1500 access_i = coa_i->access;
1502 for (int j = 0; j < dep->from->filters.size(); ++j) {
1503 pdg::call_or_access *coa_j;
1504 pdg::access *access_j;
1506 coa_j = dep->from->filters[j];
1507 assert(coa_j->type == pdg::call_or_access::t_access);
1508 access_j = coa_j->access;
1510 if (!is_same_filter(access_i, access_j,
1511 dep->relation->map))
1512 continue;
1513 dep_rel = isl_map_equate(dep_rel, isl_dim_in, n_in + j,
1514 isl_dim_out, n_out + i);
1515 found = true;
1516 any = true;
1519 if (!found)
1520 dep_rel = isl_map_eliminate(dep_rel, isl_dim_out,
1521 n_out + i, 1);
1524 if (any) {
1525 isl_map_free(dep->relation->map);
1526 dep->relation->map = dep_rel;
1527 } else
1528 isl_map_free(dep_rel);
1531 /* Insert equalities between source filters and sink filters
1532 * of dependences, whenever we are able to detect that they are the same.
1534 * We currently don't introduce any such equalities in dependences
1535 * that involve control variables. Both these control variables and
1536 * the filters will be treated as "dynamic controls" in pn2adg
1537 * and it probably needs to be tweaked to be able to handle two sets
1538 * of dynamic controls.
1540 static void insert_filter_constraints(PDG *pdg)
1542 for (int i = 0; i < pdg->dependences.size(); ++i) {
1543 pdg::dependence *dep = pdg->dependences[i];
1545 if (dep->type == pdg::dependence::uninitialized)
1546 continue;
1547 if (dep->to == dep->from)
1548 continue;
1549 if (dep->controlled_relation)
1550 continue;
1551 if (dep->to->filters.size() == 0)
1552 continue;
1553 if (dep->from->filters.size() == 0)
1554 continue;
1555 if (is_filter_access(dep->to, dep->to_access))
1556 continue;
1557 insert_filter_constraints(dep);
1561 int main(int argc, char * argv[])
1563 isl_ctx *ctx;
1564 FILE *in = stdin, *out = stdout;
1565 int c, ind = 0;
1566 PDG *pdg;
1567 struct pn_options *options = pn_options_new_with_defaults();
1568 bool evaluate = true;
1570 argc = pn_options_parse(options, argc, argv, ISL_ARG_ALL);
1572 if (!options->reuse)
1573 options->propagate = 0;
1575 if (options->input && strcmp(options->input, "-")) {
1576 in = fopen(options->input, "r");
1577 assert(in);
1578 if (!options->output) {
1579 int len = strlen(options->input);
1580 if (len > 5 && !strcmp(options->input+len-5, ".yaml"))
1581 len -= 5;
1582 options->output = (char *)malloc(len+9+1);
1583 strncpy(options->output, options->input, len);
1584 strcpy(options->output+len, options->reuse ? "_pn.yaml" : "_cpn.yaml");
1588 ctx = isl_ctx_alloc_with_options(&pn_options_args, options);
1589 pdg = PDG::Load(in, ctx);
1590 assert(pdg);
1591 int nparam = pdg->params.size();
1593 if (options->propagate)
1594 copy_propagation(pdg);
1596 compute_filter_sources(pdg);
1597 for (int i = 0; i < pdg->arrays.size(); ++i)
1598 find_deps(pdg, pdg->arrays[i], flow);
1599 extract_control_dependences(pdg);
1601 for (int i = 0; i < nparam; ++i)
1602 if (!pdg->params[i]->value) {
1603 evaluate = false;
1604 break;
1607 bool translated;
1608 if (options->reschedule) {
1609 common_dimension(pdg);
1610 translated = false;
1611 } else {
1612 set_schedule_from_prefix(pdg);
1613 translated = true;
1616 detect_reuse(pdg, options);
1617 split_multi_assignment(pdg);
1618 split_wires(pdg);
1619 merge_dependences(pdg, options);
1620 determine_dependence_properties(pdg, evaluate, translated, options);
1621 insert_filter_constraints(pdg);
1623 pdg->add_history_line("pn", argc, argv);
1625 if (options->output && strcmp(options->output, "-")) {
1626 out = fopen(options->output, "w");
1627 assert(out);
1630 pdg->Dump(out);
1631 pdg->free();
1632 delete pdg;
1633 isl_ctx_free(ctx);
1635 return 0;