update isl for change in lexicographic optimization
[isa.git] / translation.cc
blob9efbacc6e280bf757c77ab7f639289c66eed3a5c
1 #include <iostream>
2 #include <set>
3 #include <limits.h>
5 #include <isa/yaml.h>
6 #include <isa/pdg.h>
7 #include "da.h"
8 #include <isl/val.h>
9 #include <isl/space.h>
10 #include <isl/set.h>
11 #include <isl/map.h>
12 #include <isl/aff.h>
13 #include <isl/mat.h>
14 #include <isl/ilp.h>
15 #include "translation.h"
17 using namespace std;
19 namespace pdg {
21 static void set_prefix(pdg::node *node, const vector<int>& prefix, int l)
23 node->prefix.resize(0);
24 for (int j = 0; j < l-1; ++j) {
25 node->prefix.push_back(prefix[j]);
26 node->prefix.push_back(-1);
28 node->prefix.push_back(prefix[l-1]);
31 /* A comparison function for sorting pdg::nodes based on their prefix.
33 struct earlier_prefix {
34 bool operator()(pdg::node *x, pdg::node *y) {
35 for (int i = 0; i < x->prefix.size(); ++i) {
36 if (x->prefix[i] == -1 && y->prefix[i] == -1)
37 continue;
38 assert(x->prefix[i] != -1 && y->prefix[i] != -1);
39 if (x->prefix[i] < y->prefix[i])
40 return true;
41 if (x->prefix[i] > y->prefix[i])
42 return false;
44 return false;
48 /* Normalize prefix to be an alternation between statement
49 * level dimensions and loop level dimensions.
50 * Return the number of statement level dimension.
52 * Since the algorithm assumes the input prefixes are ordered
53 * lexicographically, we perform it on a sorted list of nodes.
55 int normalize_prefix(PDG *pdg)
57 int i, l, maxl;
58 vector<int> prefix;
59 vector<pdg::node *> nodes;
61 if (pdg->nodes.size() == 0)
62 return 0;
64 for (int i = 0; i < pdg->nodes.size(); ++i)
65 nodes.push_back(pdg->nodes[i]);
66 std::sort(nodes.begin(), nodes.end(), earlier_prefix());
68 l = 1;
69 for (int j = 0; j < nodes[0]->prefix.size(); ++j)
70 if (nodes[0]->prefix[j] == -1)
71 ++l;
72 prefix.resize(l);
73 maxl = l;
74 for (i = 1; i < nodes.size(); ++i) {
75 int old_l = l;
76 pdg::node *old_node = nodes[i-1];
77 pdg::node *node = nodes[i];
78 int change_l;
79 l = 1;
80 change_l = -1;
81 for (int j = 0; j < node->prefix.size(); ++j) {
82 if (change_l == -1) {
83 assert(old_node->prefix[j] <= node->prefix[j]);
84 if (old_node->prefix[j] != node->prefix[j])
85 change_l = l;
87 if (node->prefix[j] == -1)
88 ++l;
90 if (l > maxl) {
91 maxl = l;
92 prefix.resize(l);
94 set_prefix(old_node, prefix, old_l);
95 if (change_l == -1)
96 continue;
97 prefix[change_l-1]++;
98 for (int j = change_l+1; j < prefix.size(); ++j)
99 prefix[j] = 0;
101 pdg::node *node = nodes[nodes.size()-1];
102 set_prefix(node, prefix, l);
103 return maxl;
106 void set_schedule_from_prefix(PDG *pdg)
108 int statement_dims = normalize_prefix(pdg);
109 int dim = 2 * statement_dims - 1;
110 int nparam = pdg->params.size();
111 isl_ctx *ctx = pdg->get_isl_ctx();
113 assert(pdg->dimension == 0);
114 assert(pdg->dimension == pdg->statement_dimensions.size());
115 pdg->dimension = dim;
116 for (int i = 0; i < dim; ++i)
117 pdg->statement_dimensions.push_back(1-(i%2));
119 for (int i = 0; i < pdg->nodes.size(); ++i) {
120 pdg::node *node = pdg->nodes[i];
121 isl_set *set = node->source->get_isl_set(ctx);
122 isl_space *space = isl_set_get_space(set);
123 isl_map *map;
124 isl_set_free(set);
125 if (isl_space_is_wrapping(space))
126 space = isl_space_domain(isl_space_unwrap(space));
127 map = isl_map_identity(isl_space_map_from_set(space));
128 for (int j = 0; 2 * j < node->prefix.size(); ++j) {
129 map = isl_map_insert_dims(map, isl_dim_out, 2 * j, 1);
130 map = isl_map_fix_si(map, isl_dim_out, 2 * j, node->prefix[2*j]);
132 map = isl_map_add_dims(map, isl_dim_out,
133 2 * statement_dims - 1 - node->prefix.size());
134 for (int j = node->prefix.size(); j < 2 * statement_dims - 1; ++j)
135 map = isl_map_fix_si(map, isl_dim_out, j, 0);
136 node->schedule = new pdg::IslMap(map);
140 /* Create a schedule for the domains "source" based on "pos" and "scale".
141 * The "extra" dimensions of source do not appear in the schedule
142 * since they have a unique value determined by the values of the "actual"
143 * dimensions.
144 * If "source" has filters (in the range of the wrapped map), then
145 * we project out the filters so that the created schedule only applies
146 * to the actual iteration domain.
148 static pdg::IslMap *create_schedule(PDG *pdg, pdg::IslSet *source,
149 vector<int>& pos, vector<int>& scale)
151 pdg::IslMap *s;
152 isl_ctx *ctx = pdg->get_isl_ctx();
153 isl_set *set = source->get_isl_set(ctx);
154 isl_space *space = isl_set_get_space(set);
155 isl_multi_aff *ma;
156 isl_map *map;
158 if (isl_space_is_wrapping(space))
159 space = isl_space_domain(isl_space_unwrap(space));
160 space = isl_space_from_domain(space);
161 isl_set_free(set);
162 space = isl_space_add_dims(space, isl_dim_out, pdg->dimension);
163 ma = isl_multi_aff_zero(space);
164 for (int i = 0; i < pdg->dimension; ++i) {
165 isl_aff *aff;
167 if (pos[i] < 0)
168 continue;
169 aff = isl_multi_aff_get_aff(ma, i);
170 aff = isl_aff_set_coefficient_si(aff, isl_dim_in,
171 pos[i], scale[i]);
172 ma = isl_multi_aff_set_aff(ma, i, aff);
175 map = isl_map_from_multi_aff(ma);
176 s = new pdg::IslMap(map);
178 return s;
181 static pdg::IslMap *pull_back_schedule(PDG *pdg, pdg::IslSet *source,
182 pdg::IslMap *schedule, __isl_keep isl_map *map)
184 isl_ctx *ctx = pdg->get_isl_ctx();
185 isl_map *scat = schedule->get_isl_map(ctx);
186 isl_basic_map *aff;
187 isl_mat *mat;
188 int dim = pdg->dimension;
189 int this_dim = isl_map_dim(map, isl_dim_in);
190 vector<int> pos(dim);
191 vector<int> scale(dim);
192 // k: position in pos
193 int k = 0, j = 0;
194 isl_val *v;
196 map = isl_map_copy(map);
197 map = isl_map_apply_range(map, scat);
198 aff = isl_map_affine_hull(map);
199 aff = isl_basic_map_remove_divs(aff);
200 mat = isl_basic_map_equalities_matrix(aff, isl_dim_in, isl_dim_out,
201 isl_dim_div, isl_dim_param, isl_dim_cst);
202 isl_basic_map_free(aff);
204 for (j = 0; j < this_dim; ++j) {
205 int s;
206 int m;
207 int min_m = k;
208 int max_m = j + dim - this_dim;
210 for (m = min_m; m <= max_m; ++m) {
211 int row;
212 for (row = 0; row < isl_mat_rows(mat); ++row) {
213 int s_v, i_v;
214 v = isl_mat_get_element_val(mat,
215 row, this_dim + m);
216 s_v = isl_val_get_num_si(v);
217 isl_val_free(v);
218 if (s_v == 0)
219 continue;
220 v = isl_mat_get_element_val(mat, row, j);
221 i_v = isl_val_get_num_si(v);
222 isl_val_free(v);
223 if (i_v == 0)
224 continue;
225 if (s_v < 0)
226 s_v = -s_v;
227 if (i_v < 0)
228 i_v = -i_v;
229 if (s_v == 1)
230 s = i_v;
231 else if (i_v % s_v == 0)
232 s = i_v / s_v;
233 else
234 s = 1;
235 break;
237 if (row < isl_mat_rows(mat))
238 break;
240 if (m > max_m)
241 break;
242 for ( ; k < m; ++k)
243 pos[k] = -1;
244 scale[k] = s;
245 pos[k++] = j;
248 isl_mat_free(mat);
250 for ( ; j < this_dim; ++j) {
251 scale[k] = 1;
252 pos[k++] = j;
254 for ( ; k < dim; ++k)
255 pos[k] = -1;
257 return create_schedule(pdg, source, pos, scale);
260 /* Return the dimension of the iteration domain of "node".
261 * If node->source is a wrapped map, then the iteration domain
262 * is in the domain of that map.
264 static int source_dim(pdg::node *node)
266 isl_space *space = node->source->get_dim();
267 int d;
269 if (isl_space_is_wrapping(space)) {
270 space = isl_space_unwrap(space);
271 d = isl_space_dim(space, isl_dim_in);
272 } else
273 d = isl_space_dim(space, isl_dim_set);
274 isl_space_free(space);
275 return d;
278 void common_dimension(PDG *pdg)
280 isl_ctx *ctx = pdg->get_isl_ctx();
281 int dim = pdg->dimension;
282 for (int i = 0; i < pdg->nodes.size(); ++i) {
283 pdg::node *node = pdg->nodes[i];
284 int dim_i = source_dim(node);
285 if (dim_i > dim)
286 dim = dim_i;
288 assert(pdg->dimension == pdg->statement_dimensions.size());
289 for (int i = pdg->dimension; i < dim; ++i)
290 pdg->statement_dimensions.push_back(0);
291 pdg->dimension = dim;
292 vector<int> pos(dim);
293 vector<int> scale(dim);
294 for (int i = 0; i < dim; ++i) {
295 scale[i] = 1;
296 pos[i] = i;
299 int todo = pdg->nodes.size();
300 for (int i = 0; i < pdg->nodes.size(); ++i) {
301 pdg::node *node = pdg->nodes[i];
302 if (source_dim(node) != dim)
303 continue;
304 node->schedule = create_schedule(pdg, node->source, pos, scale);
305 --todo;
306 break;
309 while (todo) {
310 pdg::dependence *maxdep = NULL;
311 vector<int> maxw(4);
312 vector<int> w(4);
313 maxw[0] = -1;
314 maxw[1] = -1;
315 maxw[2] = -1;
316 maxw[3] = -1;
317 w[0] = -1;
318 w[1] = -1;
319 w[2] = -1;
320 w[3] = -1;
321 for (int i = 0; i < pdg->dependences.size(); ++i) {
322 pdg::dependence *dep = pdg->dependences[i];
323 if (dep->type == pdg::dependence::uninitialized)
324 continue;
325 pdg::IslMap *rel = dep->relation;
326 if (dep->to->schedule && !dep->from->schedule) {
327 w[0] = rel->output();
328 w[1] = rel->input();
329 w[2] = 1;
330 } else if (dep->from->schedule && !dep->to->schedule) {
331 w[0] = rel->input();
332 w[1] = rel->output();
333 w[2] = 1;
334 } else
335 continue;
336 w[3] = dep->array ? dep->array->dims.size() : 0;
337 if (maxw < w) {
338 maxw = w;
339 maxdep = dep;
342 pdg::dependence *dep = maxdep;
343 if (!dep) {
344 int maxi = -1;
345 int maxdim = -1;
346 for (int i = 0; i < pdg->nodes.size(); ++i) {
347 pdg::node *node = pdg->nodes[i];
348 int dim_i;
349 if (node->schedule)
350 continue;
351 dim_i = source_dim(node);
352 if (dim_i > maxdim) {
353 maxdim = dim_i;
354 maxi = i;
357 assert(maxi != -1);
358 pdg::node *node = pdg->nodes[maxi];
359 for (int i = node->source->dim(); i < pos.size(); ++i)
360 pos[i] = -1;
361 node->schedule = create_schedule(pdg, node->source, pos, scale);
362 for (int i = node->source->dim(); i < pos.size(); ++i)
363 pos[i] = i;
364 fprintf(stderr, "WARNING: disconnected dependence graph\n");
365 } else {
366 isl_map *dep_map = dep->relation->get_isl_map(ctx);
367 if (dep->to->schedule) {
368 dep->from->schedule = pull_back_schedule(pdg,
369 dep->from->source,
370 dep->to->schedule, dep_map);
371 } else {
372 dep_map = isl_map_reverse(dep_map);
373 dep->to->schedule = pull_back_schedule(pdg,
374 dep->to->source,
375 dep->from->schedule, dep_map);
377 isl_map_free(dep_map);
379 --todo;
384 struct dvector {
385 isl_set *d;
387 dvector() : d(NULL) {}
388 dvector(__isl_take isl_set *d) : d(d) {}
389 dvector(const dvector &copy) {
390 d = isl_set_copy(copy.d);
392 dvector &operator= (const dvector &other) {
393 isl_set_free(d);
394 d = isl_set_copy(other.d);
395 return *this;
397 virtual ~dvector() {
398 isl_set_free(d);
401 bool combine(const dvector &dv, const dvector &offset);
404 void operator-= (dvector &d1, const dvector &d2)
406 isl_set *neg = isl_set_neg(isl_set_copy(d2.d));
407 d1.d = isl_set_sum(d1.d, neg);
410 dvector operator- (const dvector &d)
412 return dvector(isl_set_neg(isl_set_copy(d.d)));
415 void operator+= (dvector &d1, const dvector &d2)
417 d1.d = isl_set_sum(d1.d, isl_set_copy(d2.d));
420 dvector operator+ (const dvector &d1, const dvector &d2)
422 return dvector(isl_set_sum(isl_set_copy(d1.d), isl_set_copy(d2.d)));
425 /* replace by dv + offset if dv + offset is smaller
426 * return true if dv + offset was smaller
428 bool dvector::combine(const dvector &dv, const dvector &offset)
430 int equal;
431 dvector new_v = dv + offset;
432 new_v.d = isl_set_union(new_v.d, isl_set_copy(d));
433 new_v.d = isl_set_lexmin(new_v.d);
434 equal = isl_set_is_equal(new_v.d, d);
435 assert(equal >= 0);
436 if (equal)
437 return false;
438 new_v.d = isl_set_remove_divs(new_v.d);
439 new_v.d = isl_set_lexmin(new_v.d);
440 *this = new_v;
441 return true;
444 struct wdvector : dvector {
445 int w;
447 wdvector() : w(0), dvector(NULL) {}
448 wdvector(int w, __isl_take isl_set *d) : w(w), dvector(d) {}
451 wdvector operator+ (const wdvector &d1, const dvector &d2)
453 return wdvector(d1.w,
454 isl_set_sum(isl_set_copy(d1.d), isl_set_copy(d2.d)));
457 /* Fairly arbitrary, but deterministic sorting of the nodes.
458 * In particular, the order does not depend on pointer values.
460 struct smaller_node_nr
462 bool operator()(const pdg::node* n1, const pdg::node* n2) const {
463 return n1->nr < n2->nr;
467 typedef map<pdg::node *,
468 map<pdg::node *, wdvector, smaller_node_nr>,
469 smaller_node_nr>::iterator d_graph_iterator;
471 struct d_graph {
472 map<pdg::node *,
473 map<pdg::node *, wdvector, smaller_node_nr>, smaller_node_nr> data;
475 void update(pdg::node *from, pdg::node *to, __isl_take isl_set *ddv,
476 int weight);
478 void minimize();
479 void collect_related_nodes(set<pdg::node *> &nodes, pdg::node *node);
482 void d_graph::update(pdg::node *from, pdg::node *to,
483 __isl_take isl_set *ddv, int weight)
485 assert(ddv);
486 if (data[from].find(to) == data[from].end())
487 data[from][to] = wdvector(weight, ddv);
488 else {
489 data[from][to].w += weight;
490 data[from][to].d = isl_set_union(data[from][to].d, ddv);
494 void d_graph::minimize()
496 d_graph_iterator i;
497 for (i = data.begin(); i != data.end(); ++i) {
498 pdg::node *from = (*i).first;
499 map<pdg::node *, wdvector>::iterator j;
500 for (j = data[from].begin(); j != data[from].end(); ++j) {
501 (*j).second.d = isl_set_lexmin((*j).second.d);
502 (*j).second.d = isl_set_remove_divs((*j).second.d);
503 (*j).second.d = isl_set_lexmin((*j).second.d);
504 (*j).second.d = isl_set_coalesce((*j).second.d);
509 void d_graph::collect_related_nodes(set<pdg::node *> &nodes,
510 pdg::node *node)
512 vector<pdg::node *> todo;
514 todo.push_back(node);
516 while (!todo.empty()) {
517 pdg::node *node = todo.back();
518 todo.pop_back();
519 if (nodes.find(node) != nodes.end())
520 continue;
522 nodes.insert(node);
524 d_graph_iterator i;
525 map<pdg::node *, wdvector>::iterator j;
526 for (j = data[node].begin(); j != data[node].end(); ++j) {
527 pdg::node *node2 = (*j).first;
528 if (nodes.find(node2) != nodes.end())
529 continue;
530 todo.push_back(node2);
532 for (i = data.begin(); i != data.end(); ++i) {
533 pdg::node *node2 = (*i).first;
534 if (nodes.find(node2) != nodes.end())
535 continue;
536 if ((*i).second.find(node) == (*i).second.end())
537 continue;
538 todo.push_back(node2);
543 struct combiner {
544 PDG *pdg;
545 d_graph &graph;
546 /* dependence distance offsets used during moving */
547 map<pdg::node *, dvector> move_offsets;
548 /* the relative offsets */
549 map<pdg::node *, map<pdg::node *, dvector> > delays;
550 /* the original distance vectors */
551 map<pdg::node *, map<pdg::node *, dvector> > distances;
552 /* the final offsets */
553 map<pdg::node *, dvector> offsets;
554 int n_nodes;
555 bool move;
556 /* space of schedule domain */
557 isl_space *space;
559 combiner(PDG *pdg, d_graph& distances, int n_nodes, bool move,
560 __isl_keep isl_space *space) :
561 pdg(pdg), graph(distances), n_nodes(n_nodes), move(move),
562 space(space) {}
564 void combine();
566 void compute_move_offsets();
567 dvector compute_relative_offset(pdg::node* from, pdg::node *to,
568 bool do_move);
569 void set_relative_offset(pdg::node* from, pdg::node *to);
570 void update_graph(pdg::node* from, pdg::node *to);
571 void compute_absolute_offsets();
572 void handle_zero_dependences();
573 void handle_negative_offsets();
576 static __isl_give isl_set *zero_set(__isl_take isl_space *dim)
578 isl_set *set;
579 int n = isl_space_dim(dim, isl_dim_set);
580 set = isl_set_universe(dim);
581 for (int i = 0; i < n; ++i)
582 set = isl_set_fix_si(set, isl_dim_set, i, 0);
583 return set;
586 dvector combiner::compute_relative_offset(pdg::node* from,
587 pdg::node *to, bool do_move)
589 dvector delay;
590 map<pdg::node *, dvector> d;
591 bool progress = true;
592 map<pdg::node *, dvector>::iterator i;
594 d[from] = dvector(zero_set(isl_set_get_space(graph.data[from][to].d)));
596 for (int k = 0; k < n_nodes && progress; ++k) {
597 map<pdg::node *, wdvector>::iterator j;
598 progress = false;
599 for (i = d.begin(); i != d.end(); ++i) {
600 pdg::node *a = (*i).first;
601 for (j = graph.data[a].begin();
602 j != graph.data[a].end(); ++j) {
603 pdg::node *b = (*j).first;
604 if (do_move &&
605 move_offsets.find(a) != move_offsets.end())
606 (*j).second -= move_offsets[a];
607 if (d.find(b) == d.end()) {
608 progress = true;
609 d[b] = (*j).second + d[a];
610 } else {
611 bool p;
612 p = d[b].combine((*j).second, d[a]);
613 progress = progress || p;
615 if (do_move &&
616 move_offsets.find(a) != move_offsets.end())
617 (*j).second += move_offsets[a];
622 /* d[from] + d[from] < d[from] iff d[from] < 0 */
623 bool lexneg = d[from].combine(d[from], d[from]);
624 if (!do_move)
625 assert(!lexneg);
627 if (!lexneg)
628 delay = -d[to];
630 return delay;
633 void combiner::set_relative_offset(pdg::node* from, pdg::node *to)
635 dvector delay;
636 if (move)
637 delay = compute_relative_offset(from, to, true);
638 if (!delay.d)
639 delay = compute_relative_offset(from, to, false);
640 assert(delay.d);
641 delays[from][to] = delay;
644 void combiner::update_graph(pdg::node* from, pdg::node *to)
646 dvector offset = delays[from][to];
647 dvector neg_offset = -offset;
649 map<pdg::node *, wdvector>::iterator j;
650 for (j = graph.data[to].begin(); j != graph.data[to].end(); ++j) {
651 if ((*j).first == from)
652 continue;
653 if (graph.data[from].find((*j).first) == graph.data[from].end())
654 graph.data[from][(*j).first] = (*j).second + neg_offset;
655 else
656 graph.data[from][(*j).first].combine((*j).second,
657 neg_offset);
660 graph.data.erase(to);
662 d_graph_iterator i;
663 for (i = graph.data.begin(); i != graph.data.end(); ++i) {
664 if ((*i).second.find(to) == (*i).second.end())
665 continue;
666 if ((*i).first != from) {
667 if ((*i).second.find(from) == (*i).second.end())
668 (*i).second[from] = (*i).second[to] + offset;
669 else
670 (*i).second[from].combine((*i).second[to], offset);
672 (*i).second.erase(to);
675 --n_nodes;
678 void combiner::compute_absolute_offsets()
680 pdg::node *init = (*graph.data.begin()).first;
681 vector<pdg::node *> todo;
682 todo.push_back(init);
683 offsets[init] = dvector(zero_set(isl_space_copy(space)));
685 while (!todo.empty()) {
686 pdg::node *n = todo.back();
687 todo.pop_back();
688 if (delays.find(n) == delays.end())
689 continue;
691 map<pdg::node *, dvector>::iterator i;
692 for (i = delays[n].begin(); i != delays[n].end(); ++i) {
693 offsets[(*i).first] = offsets[n] + (*i).second;
694 todo.push_back((*i).first);
699 void combiner::handle_zero_dependences()
701 map<pdg::node *, set<pdg::node *> > succ;
702 map<pdg::node *, int > prec;
703 map<pdg::node *, map<pdg::node *, dvector> >::iterator i;
704 map<pdg::node *, dvector>::iterator j;
705 for (j = offsets.begin(); j != offsets.end(); ++j)
706 prec[(*j).first] = 0;
708 for (i = distances.begin(); i != distances.end(); ++i)
709 for (j = (*i).second.begin(); j != (*i).second.end(); ++j) {
710 distances[(*i).first][(*j).first] +=
711 offsets[(*j).first];
712 distances[(*i).first][(*j).first] -=
713 offsets[(*i).first];
714 isl_set *test = distances[(*i).first][(*j).first].d;
715 isl_set *zero = zero_set(isl_set_get_space(test));
716 zero = isl_set_intersect(zero, isl_set_copy(test));
717 int has_zero = !isl_set_is_empty(zero);
718 isl_set_free(zero);
719 if (has_zero) {
720 succ[(*i).first].insert((*j).first);
721 prec[(*j).first]++;
725 map<pdg::node *, int> final;
726 for (j = offsets.begin(); j != offsets.end(); ++j) {
727 final[(*j).first] = 0;
730 while (!prec.empty()) {
731 map<pdg::node *, int >::iterator i;
732 for (i = prec.begin(); (*i).second > 0; ++i)
734 set<pdg::node *>::iterator j;
735 for (j = succ[(*i).first].begin();
736 j != succ[(*i).first].end(); ++j) {
737 prec[(*j)]--;
738 if (final[(*j)] <= final[(*i).first])
739 final[(*j)] = final[(*i).first] + 1;
741 prec.erase(i);
744 int dim = isl_set_dim((*offsets.begin()).second.d, isl_dim_set);
745 for (j = offsets.begin(); j != offsets.end(); ++j) {
746 (*j).second.d = isl_set_add_dims((*j).second.d, isl_dim_set, 1);
747 (*j).second.d = isl_set_fix_si((*j).second.d, isl_dim_set, dim,
748 final[(*j).first]);
752 /* Remove negative offsets by shifting all offsets over the opposite
753 * of the most negative offsets in each direction.
755 void combiner::handle_negative_offsets()
757 int dim = isl_set_dim((*offsets.begin()).second.d, isl_dim_set);
758 isl_space *space;
759 isl_set *shift;
760 isl_set *set;
761 map<pdg::node *, dvector>::iterator j;
763 space = isl_set_get_space((*offsets.begin()).second.d);
764 set = isl_set_universe(isl_space_copy(space));
765 space = isl_space_params(space);
766 space = isl_space_add_unnamed_tuple_ui(space, 0);
767 shift = isl_set_universe(space);
769 for (int i = 0; i < dim; ++i)
770 set = isl_set_fix_si(set, isl_dim_set, i, 0);
772 for (j = offsets.begin(); j != offsets.end(); ++j)
773 set = isl_set_union(set, isl_set_copy((*j).second.d));
775 for (int i = 0; i < dim; ++i) {
776 isl_pw_aff *pa = isl_set_dim_min(isl_set_copy(set), i);
777 pa = isl_pw_aff_coalesce(pa);
778 isl_set *shift_i = isl_set_from_pw_aff(pa);
779 shift = isl_set_flat_product(shift, shift_i);
782 shift = isl_set_neg(shift);
783 shift = isl_set_gist_params(shift, pdg->get_context_isl_set());
784 for (j = offsets.begin(); j != offsets.end(); ++j)
785 (*j).second.d = isl_set_sum((*j).second.d, isl_set_copy(shift));
787 isl_set_free(set);
788 isl_set_free(shift);
791 /* Builds a relation that connects iterations of D to the next iteration */
792 static __isl_give isl_map *next_iteration_map(__isl_take isl_set *dom)
794 isl_space *dims = isl_set_get_space(dom);
795 isl_map *lt = isl_map_lex_lt(dims);
796 lt = isl_map_intersect_domain(lt, isl_set_copy(dom));
797 lt = isl_map_intersect_range(lt, isl_set_copy(dom));
798 lt = isl_map_partial_lexmax(lt, dom, NULL);
799 return lt;
802 void combiner::compute_move_offsets()
804 d_graph_iterator i;
805 isl_ctx *ctx = pdg->get_isl_ctx();
807 for (i = graph.data.begin(); i != graph.data.end(); ++i) {
808 pdg::node *node = (*i).first;
809 isl_set *dom = node->source->get_isl_set(ctx);
810 isl_set *context = pdg->get_context_isl_set();
811 dom = isl_set_intersect_params(dom, context);
812 isl_map *scat = (*i).first->schedule->get_isl_map(ctx);
813 dom = isl_set_apply(dom, scat);
814 isl_map *next = next_iteration_map(dom);
815 isl_set *step = isl_map_deltas(next);
816 step = isl_set_lexmin(step);
817 if (isl_set_is_empty(step))
818 isl_set_free(step);
819 else
820 move_offsets[node] = dvector(step);
824 void combiner::combine()
826 d_graph_iterator i;
827 map<pdg::node *, wdvector>::iterator j;
829 if (move)
830 compute_move_offsets();
832 for (i = graph.data.begin(); i != graph.data.end(); ++i)
833 for (j = (*i).second.begin(); j != (*i).second.end(); ++j)
834 distances[(*i).first][(*j).first] = (*j).second;
836 while (n_nodes > 1) {
837 int max = -1;
838 pdg::node* max_from = NULL;
839 pdg::node* max_to = NULL;
840 d_graph_iterator i;
841 map<pdg::node *, wdvector>::iterator j;
842 for (i = graph.data.begin(); i != graph.data.end(); ++i)
843 for (j = (*i).second.begin();
844 j != (*i).second.end(); ++j) {
845 if ((*j).second.w <= max)
846 continue;
847 max = (*j).second.w;
848 max_from = (*i).first;
849 max_to = (*j).first;
851 assert(max_from);
852 assert(max_to);
853 set_relative_offset(max_from, max_to);
854 update_graph(max_from, max_to);
857 compute_absolute_offsets();
858 handle_zero_dependences();
859 handle_negative_offsets();
862 bool translate(PDG *pdg, bool move)
864 isl_ctx *ctx = pdg->get_isl_ctx();
865 isl_space *space;
866 d_graph distances;
868 if (pdg->nodes.size() == 0)
869 return true;
871 space = isl_map_get_space(pdg->nodes[0]->schedule->map);
872 space = isl_space_range(space);
874 for (int i = 0; i < pdg->dependences.size(); ++i) {
875 pdg::dependence *dep = pdg->dependences[i];
876 if (dep->type == pdg::dependence::uninitialized)
877 continue;
878 if (dep->from == dep->to)
879 continue;
880 int weight = dep->type == pdg::dependence::anti ? 0 : 1;
881 pdg::node* from = dep->from;
882 pdg::node* to = dep->to;
883 isl_set *ddv;
884 isl_map *scat;
885 isl_map *dep_map = dep->relation->get_isl_map(ctx);
886 scat = from->schedule->get_isl_map(ctx);
887 dep_map = isl_map_apply_domain(dep_map, scat);
888 scat = to->schedule->get_isl_map(ctx);
889 dep_map = isl_map_apply_range(dep_map, scat);
890 ddv = isl_map_deltas(dep_map);
891 distances.update(from, to, ddv, weight);
894 distances.minimize();
896 set<pdg::node *> nodes_done;
897 /* split the dependence graph into connected subgraphs
898 * and compute offsets in each subgraph
900 while (nodes_done.size() < pdg->nodes.size()) {
901 set<pdg::node *> current_nodes;
902 d_graph current_distances;
903 pdg::node *node;
905 for (int i = 0; i < pdg->nodes.size(); ++i) {
906 node = pdg->nodes[i];
907 if (nodes_done.find(node) != nodes_done.end())
908 continue;
909 break;
912 distances.collect_related_nodes(current_nodes, node);
914 set<pdg::node *>::iterator i;
915 for (i = current_nodes.begin(); i != current_nodes.end(); ++i) {
916 current_distances.data[(*i)] = distances.data[(*i)];
919 combiner c(pdg, current_distances, current_nodes.size(),
920 move, space);
921 c.combine();
923 for (i = current_nodes.begin(); i != current_nodes.end(); ++i) {
924 pdg::node *node = *i;
925 nodes_done.insert(node);
927 isl_map *s = node->schedule->get_isl_map(ctx);
929 isl_space *dim = isl_set_get_space(c.offsets[node].d);
930 int d = isl_space_dim(dim, isl_dim_set) - 1;
931 isl_map *id = isl_map_identity(
932 isl_space_map_from_set(isl_space_copy(dim)));
933 isl_set *u = isl_set_universe(dim);
934 isl_map *off = isl_map_from_domain_and_range(u,
935 isl_set_copy(c.offsets[node].d));
936 id = isl_map_project_out(id, isl_dim_in, d, 1);
937 id = isl_map_fix_si(id, isl_dim_out, d, 0);
938 off = isl_map_project_out(off, isl_dim_in, d, 1);
939 off = isl_map_sum(id, off);
940 s = isl_map_apply_range(s, off);
942 delete node->schedule;
943 node->schedule = new IslMap(s);
947 pdg->statement_dimensions.push_back(1);
948 pdg->dimension++;
950 isl_space_free(space);
952 return true;