da: remove inconsistencies from dependence relations
[ppn.git] / eqv2.cc
blobc19387157e0924a17d90bbc8044956c375f5993f
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <algorithm>
5 #include <map>
6 #include <set>
7 #include <string>
8 #include <sstream>
9 #include <vaucanson/int_boolean_automaton.hh>
11 #include <isa/yaml.h>
12 #include <isa/pdg.h>
13 #include "dependence_graph.h"
14 #include "eqv2_options.h"
15 #include "msa.h"
17 #include "config.h"
19 #include <isl/constraint.h>
21 #ifdef HAVE_OMEGA_PLUS
22 #include <omega.h>
24 using namespace omega;
26 typedef std::vector<Variable_ID> varvector;
27 typedef std::vector<Global_Var_Decl *> globalvector;
29 static void create_globals(globalvector &globals, __isl_keep isl_space *dim)
31 unsigned nparam = isl_space_dim(dim, isl_dim_param);
32 for (int i = 0; i < nparam; ++i) {
33 const char *name;
34 name = isl_space_get_dim_name(dim, isl_dim_param, i);
35 globals.push_back(new Global_Var_Decl(name));
39 struct map2rel_data {
40 isl_int v;
42 varvector in;
43 varvector out;
44 varvector params;
45 varvector exists;
47 F_And *base;
50 static int add_constraint(__isl_take isl_constraint *c, void *user)
52 struct map2rel_data *data = (struct map2rel_data *) user;
53 Constraint_Handle h;
55 if (isl_constraint_is_equality(c))
56 h = data->base->add_EQ();
57 else
58 h = data->base->add_GEQ();
60 for (int i = 0; i < data->in.size(); ++i) {
61 isl_constraint_get_coefficient(c, isl_dim_in, i, &data->v);
62 h.update_coef(data->in[i], isl_int_get_si(data->v));
64 for (int i = 0; i < data->out.size(); ++i) {
65 isl_constraint_get_coefficient(c, isl_dim_out, i, &data->v);
66 h.update_coef(data->out[i], isl_int_get_si(data->v));
68 for (int i = 0; i < data->params.size(); ++i) {
69 isl_constraint_get_coefficient(c, isl_dim_param, i, &data->v);
70 h.update_coef(data->params[i], isl_int_get_si(data->v));
72 for (int i = 0; i < data->exists.size(); ++i) {
73 isl_constraint_get_coefficient(c, isl_dim_div, i, &data->v);
74 h.update_coef(data->exists[i], isl_int_get_si(data->v));
76 isl_constraint_get_constant(c, &data->v);
77 h.update_const(isl_int_get_si(data->v));
79 isl_constraint_free(c);
81 return 0;
84 static Relation basic_map2relation(isl_basic_map *bmap,
85 const Variable_ID_Tuple *globals)
87 struct map2rel_data data;
89 Relation r(isl_basic_map_dim(bmap, isl_dim_in),
90 isl_basic_map_dim(bmap, isl_dim_out));
91 F_Exists *e = r.add_exists();
92 data.base = e->add_and();
94 for (int j = 1; j <= r.n_inp(); ++j)
95 data.in.push_back(r.input_var(j));
96 for (int j = 1; j <= r.n_out(); ++j)
97 data.out.push_back(r.output_var(j));
98 for (int i = 0; i < isl_basic_map_dim(bmap, isl_dim_div); ++i)
99 data.exists.push_back(e->declare());
100 for (int i = 0; i < globals->size(); ++i)
101 data.params.push_back(r.get_local((*globals)[i+1]));
103 isl_int_init(data.v);
105 isl_basic_map_foreach_constraint(bmap, &add_constraint, &data);
107 isl_int_clear(data.v);
109 r.finalize();
110 return r;
113 static int bm2r(__isl_take isl_basic_map *bmap, void *user)
115 Relation *r = (Relation *)user;
117 *r = Union(*r, basic_map2relation(bmap, r->global_decls()));
119 isl_basic_map_free(bmap);
121 return 0;
124 static Relation map2relation(__isl_keep isl_map *map,
125 const globalvector &globals)
127 Relation r(isl_map_dim(map, isl_dim_in), isl_map_dim(map, isl_dim_out));
128 for (int i = 0; i < globals.size(); ++i)
129 r.get_local(globals[i]);
130 r.add_or();
131 r.finalize();
133 isl_map_foreach_basic_map(map, &bm2r, &r);
135 return r;
138 static void set_constraint(isl_constraint *c, Constraint_Handle h,
139 varvector &in, varvector &out, varvector &params)
141 isl_int v;
143 isl_int_init(v);
145 for (int i = 0; i < in.size(); ++i) {
146 isl_int_set_si(v, h.get_coef(in[i]));
147 isl_constraint_set_coefficient(c, isl_dim_in, i, v);
149 for (int i = 0; i < out.size(); ++i) {
150 isl_int_set_si(v, h.get_coef(out[i]));
151 isl_constraint_set_coefficient(c, isl_dim_out, i, v);
153 for (int i = 0; i < params.size(); ++i) {
154 isl_int_set_si(v, h.get_coef(params[i]));
155 isl_constraint_set_coefficient(c, isl_dim_param, i, v);
157 isl_int_set_si(v, h.get_const());
158 isl_constraint_set_constant(c, v);
160 isl_int_clear(v);
163 static void max_index(Constraint_Handle c, varvector& vv, varvector& params)
165 for (Constr_Vars_Iter cvi(c); cvi; ++cvi) {
166 Variable_ID var = (*cvi).var;
167 if (find(vv.begin(), vv.end(), var) == vv.end() &&
168 find(params.begin(), params.end(), var) == params.end())
169 vv.push_back(var);
173 static void set_constraint(isl_constraint *c, Constraint_Handle h,
174 varvector &vv, varvector &params)
176 isl_int v;
178 isl_int_init(v);
180 for (int i = 0; i < vv.size(); ++i) {
181 isl_int_set_si(v, h.get_coef(vv[i]));
182 isl_constraint_set_coefficient(c, isl_dim_set, i, v);
184 for (int i = 0; i < params.size(); ++i) {
185 isl_int_set_si(v, h.get_coef(params[i]));
186 isl_constraint_set_coefficient(c, isl_dim_param, i, v);
188 isl_int_set_si(v, h.get_const());
189 isl_constraint_set_constant(c, v);
191 isl_int_clear(v);
194 static isl_basic_set *disjunct2basic_set(DNF_Iterator &di, isl_space *dim,
195 varvector &vv, varvector &params)
197 int d = vv.size();
198 isl_constraint *c;
199 isl_basic_set *bset;
200 isl_local_space *ls;
202 for (EQ_Iterator ei = (*di)->EQs(); ei; ++ei)
203 max_index((*ei), vv, params);
204 for (GEQ_Iterator gi = (*di)->GEQs(); gi; ++gi)
205 max_index((*gi), vv, params);
207 dim = isl_space_add_dims(dim, isl_dim_set, vv.size() - d);
208 bset = isl_basic_set_universe(isl_space_copy(dim));
209 ls = isl_local_space_from_space(dim);
211 for (EQ_Iterator ei = (*di)->EQs(); ei; ++ei) {
212 c = isl_equality_alloc(isl_local_space_copy(ls));
213 set_constraint(c, (*ei), vv, params);
214 bset = isl_basic_set_add_constraint(bset, c);
216 for (GEQ_Iterator gi = (*di)->GEQs(); gi; ++gi) {
217 c = isl_inequality_alloc(isl_local_space_copy(ls));
218 set_constraint(c, (*gi), vv, params);
219 bset = isl_basic_set_add_constraint(bset, c);
222 isl_local_space_free(ls);
224 bset = isl_basic_set_project_out(bset, isl_dim_set, d, vv.size() - d);
225 vv.resize(d);
227 return bset;
230 static __isl_give isl_map *relation2map(__isl_take isl_space *dim, Relation &r)
232 varvector vv;
233 varvector params;
234 isl_ctx *ctx;
235 isl_space *dim_set;
236 isl_map *map;
238 for (int j = 1; j <= r.n_inp(); ++j)
239 vv.push_back(r.input_var(j));
240 for (int j = 1; j <= r.n_out(); ++j)
241 vv.push_back(r.output_var(j));
243 const Variable_ID_Tuple *globals = r.global_decls();
244 for (int i = 0; i < globals->size(); ++i)
245 params.push_back(r.get_local((*globals)[i+1]));
247 ctx = isl_space_get_ctx(dim);
248 dim_set = isl_space_set_alloc(ctx, params.size(), vv.size());
249 map = isl_map_empty(isl_space_copy(dim));
251 for (DNF_Iterator di(r.query_DNF()); di; ++di) {
252 isl_basic_set *bset;
253 isl_basic_map *bmap;
255 bset = disjunct2basic_set(di, isl_space_copy(dim_set), vv, params);
256 bmap = isl_basic_map_from_basic_set(bset, isl_space_copy(dim));
257 map = isl_map_union(map, isl_map_from_basic_map(bmap));
260 isl_space_free(dim_set);
261 isl_space_free(dim);
263 return map;
266 /* Compute transitive closure using Omega+.
267 * Note that the result computed by Omega also contains the identity
268 * mapping on the intersection of domain and range, but we will include
269 * the entire identity mapping later, so this shouldn't be a problem.
271 static __isl_give isl_map *omega_closure(__isl_take isl_map *map)
273 isl_ctx *ctx = isl_map_get_ctx(map);
274 struct options *options = isl_ctx_peek_eqv2_options(ctx);
275 isl_space *dim;
276 globalvector globals;
278 dim = isl_map_get_space(map);
279 create_globals(globals, dim);
281 Relation R = map2relation(map, globals);
282 isl_map_free(map);
284 Relation TC;
285 if (options->try_lower) {
286 int exact;
287 TC = TransitiveClosure(copy(R));
288 Relation test = Composition(copy(TC), copy(R));
290 exact = TC.is_exact() &&
291 Must_Be_Subset(copy(R), copy(TC)) &&
292 Must_Be_Subset(test, copy(TC));
293 if (!exact)
294 TC = Upper_Bound(ApproxClosure(R));
295 } else
296 TC = Upper_Bound(ApproxClosure(R));
298 map = relation2map(dim, TC);
300 return map;
302 #endif
304 /* Compute transitive closure */
305 static __isl_give isl_map *closure(__isl_take isl_map *map)
307 isl_ctx *ctx = isl_map_get_ctx(map);
308 struct options *options = isl_ctx_peek_eqv2_options(ctx);
310 #ifdef HAVE_OMEGA_PLUS
311 if (options->omega)
312 return omega_closure(map);
313 #endif
315 return isl_map_transitive_closure(map, NULL);
318 using namespace vcsn::int_boolean_automaton;
319 using namespace vcsn;
321 template <class Exp_, class Dispatch_>
322 class acc_visitor : public algebra::KRatExpMatcher<
323 acc_visitor<Exp_, Dispatch_>, Exp_, isl_map *, Dispatch_ >
325 public:
326 typedef typename Exp_::monoid_elt_value_t monoid_elt_value_t;
327 typedef acc_visitor<Exp_, Dispatch_> this_class;
328 typedef isl_map * return_type;
330 private:
331 const MSA &msa;
333 public:
334 acc_visitor(const MSA &msa) : msa(msa) {}
336 INHERIT_CONSTRUCTORS(this_class, Exp_, isl_map *, Dispatch_);
338 MATCH__(Product, lhs, rhs) {
339 return isl_map_apply_range(match(lhs), match(rhs));
340 } END
342 MATCH__(Sum, lhs, rhs) {
343 return isl_map_union(match(lhs), match(rhs));
344 } END
346 MATCH_(Star, node) {
347 isl_space *dim;
348 isl_map *map;
349 map = closure(match(node));
350 dim = isl_map_get_space(map);
351 return isl_map_union(map, isl_map_identity(dim));
352 } END
354 MATCH__(LeftWeight, w, node) {
355 assert(0);
356 return 0;
357 } END
359 MATCH__(RightWeight, node, w) {
360 assert(0);
361 return 0;
362 } END
364 MATCH_(Constant, m) {
365 isl_map *map;
366 typename monoid_elt_value_t::const_iterator i = m.begin();
367 assert(i != m.end());
368 map = isl_map_copy(msa.firing[*i]);
369 ++i;
370 assert(i == m.end());
372 return map;
373 } END
375 /* By construction, there should always be a path */
376 MATCH(Zero) {
377 assert(0);
378 return 0;
379 } END
381 /* There can be no zero-length path */
382 MATCH(One) {
383 assert(0);
384 return 0;
385 } END
388 template<typename Exp>
389 isl_map *accessibility(const MSA &msa, const Exp &kexp)
391 acc_visitor<Exp, algebra::DispatchFunction<Exp> > m(msa);
392 return m.match(kexp);
395 static unsigned update_out_dim(pdg::PDG *pdg, unsigned out_dim)
397 for (int i = 0; i < pdg->arrays.size(); ++i) {
398 pdg::array *array = pdg->arrays[i];
399 if (array->type != pdg::array::output)
400 continue;
401 if (array->dims.size() + 1 > out_dim)
402 out_dim = array->dims.size() + 1;
405 return out_dim;
408 /* The input arrays of the two programs are supposed to be the same,
409 * so they should at least have the same dimension. Make sure
410 * this is true, because we depend on it later on.
412 static int check_input_arrays(dependence_graph *dg1, dependence_graph *dg2)
414 for (int i = 0; i < dg1->input_computations.size(); ++i)
415 for (int j = 0; j < dg2->input_computations.size(); ++j) {
416 if (strcmp(dg1->input_computations[i]->operation,
417 dg2->input_computations[j]->operation))
418 continue;
419 if (dg1->input_computations[i]->dim ==
420 dg2->input_computations[j]->dim)
421 continue;
422 fprintf(stderr,
423 "input arrays \"%s\" do not have the same dimension\n",
424 dg1->input_computations[i]->operation);
425 return -1;
428 return 0;
431 /* Compute a map between the domains of the output nodes of
432 * the dependence graphs that expresses that array1 in dg1
433 * and array2 in dg2 are equal.
434 * This map is then returned as a set.
436 static __isl_give isl_set *compute_equal_array(
437 dependence_graph *dg1, dependence_graph *dg2, int array1, int array2)
439 const char *array_name = dg1->output_arrays[array1];
440 isl_set *out1 = isl_set_copy(dg1->out->domain);
441 isl_set *out2 = isl_set_copy(dg2->out->domain);
442 unsigned dim1 = isl_set_n_dim(out1);
443 unsigned dim2 = isl_set_n_dim(out2);
445 out1 = isl_set_fix_dim_si(out1, dim1 - 1, array1);
446 out2 = isl_set_fix_dim_si(out2, dim2 - 1, array2);
447 out1 = isl_set_remove_dims(out1, isl_dim_set, dim1 - 1, 1);
448 out2 = isl_set_remove_dims(out2, isl_dim_set, dim2 - 1, 1);
449 int equal = isl_set_is_equal(out1, out2);
450 isl_set_free(out1);
451 isl_set_free(out2);
452 assert(equal >= 0);
453 if (!equal) {
454 fprintf(stderr, "different output domains for array %s\n",
455 array_name);
456 return NULL;
459 out1 = isl_set_copy(dg1->out->domain);
460 out2 = isl_set_copy(dg2->out->domain);
461 out1 = isl_set_fix_dim_si(out1, dim1 - 1, array1);
462 out2 = isl_set_fix_dim_si(out2, dim2 - 1, array2);
463 out1 = isl_set_coalesce(out1);
464 out2 = isl_set_coalesce(out2);
465 isl_space *dim = isl_space_map_from_set(isl_set_get_space(out2));
466 isl_map *id = isl_map_identity(dim);
467 id = isl_map_remove_dims(id, isl_dim_in, isl_map_n_in(id) - 1, 1);
468 id = isl_map_apply_domain(id, isl_map_copy(id));
469 id = isl_map_intersect_domain(id, out1);
470 id = isl_map_intersect_range(id, out2);
472 return isl_map_wrap(id);
475 /* Compute a map between the domains of the output nodes of
476 * the dependence graphs that expresses that arrays with
477 * the same names in both graphs are equal.
478 * The map is returned as a set.
480 static __isl_give isl_set *compute_equal_output(
481 dependence_graph *dg1, dependence_graph *dg2)
483 int i1 = 0, i2 = 0;
484 isl_space *dim;
485 isl_map *map;
486 isl_set *equal_output;
487 unsigned d;
489 dim = isl_set_get_space(dg1->out->domain);
490 d = isl_space_dim(dim, isl_dim_set);
491 map = isl_map_empty(isl_space_map_from_set(dim));
492 equal_output = isl_map_wrap(map);
494 while (i1 < dg1->output_arrays.size() || i2 < dg2->output_arrays.size()) {
495 int cmp;
496 cmp = i1 == dg1->output_arrays.size() ? 1 :
497 i2 == dg2->output_arrays.size() ? -1 :
498 strcmp(dg1->output_arrays[i1], dg2->output_arrays[i2]);
499 if (cmp < 0) {
500 fprintf(stdout,
501 "Array \"%s\" only in program 1; not checked\n",
502 dg1->output_arrays[i1]);
503 ++i1;
504 } else if (cmp > 0) {
505 fprintf(stdout,
506 "Array \"%s\" only in program 2; not checked\n",
507 dg2->output_arrays[i2]);
508 ++i2;
509 } else {
510 isl_set *eq_array;
511 eq_array = compute_equal_array(dg1, dg2, i1, i2);
512 equal_output = isl_set_union(equal_output, eq_array);
513 ++i1;
514 ++i2;
518 equal_output = isl_set_set_tuple_name(equal_output, "s0");
520 return equal_output;
523 static int check_equivalence(isl_ctx *ctx,
524 dependence_graph *dg1, dependence_graph *dg2)
526 int root;
527 MSA msa;
528 isl_printer *p;
529 unsigned d;
530 int ok = 1;
532 if (check_input_arrays(dg1, dg2))
533 return -1;
535 p = isl_printer_to_file(ctx, stdout);
537 root = msa.add(dg1->out, dg2->out);
539 alphabet_t alpha;
540 for (int i = 0; i < msa.firing.size(); ++i)
541 alpha.insert(i);
543 automaton_t a = make_automaton(alpha);
544 std::vector<hstate_t> state;
545 for (int i = 0; i < msa.state.size(); ++i)
546 state.push_back(a.add_state());
548 for (int i = 0; i < msa.transition.size(); ++i) {
549 int s1 = msa.transition[i].first.first;
550 int s2 = msa.transition[i].first.second;
551 int f = msa.transition[i].second;
552 a.add_letter_transition(state[s1], state[s2], f);
555 a.set_initial(state[root]);
557 isl_set *equal_output;
558 equal_output = compute_equal_output(dg1, dg2);
560 for (int i = 0; i < msa.input_state.size(); ++i) {
561 isl_map *acc;
562 isl_set *set;
563 isl_map *map;
564 isl_map *id;
566 a.set_final(state[msa.input_state[i]]);
567 rat_exp_t ratexp = aut_to_exp(a);
568 a.clear_final();
570 acc = accessibility(msa, ratexp.value());
571 set = isl_set_apply(isl_set_copy(equal_output),
572 isl_map_copy(acc));
573 map = isl_set_unwrap(set);
575 id = isl_map_identity(isl_map_get_space(map));
576 map = isl_map_subtract(map, id);
578 set = isl_map_wrap(map);
579 set = isl_set_set_tuple_name(set,
580 isl_map_get_tuple_name(acc, isl_dim_out));
581 set = isl_set_apply(set, isl_map_reverse(acc));
582 d = isl_set_dim(set, isl_dim_set) / 2;
583 set = isl_set_remove_dims(set, isl_dim_set, d, d);
584 if (!isl_set_is_empty(set)) {
585 ok = 0;
586 isl_printer_print_str(p, "NOT equivalent");
587 isl_printer_end_line(p);
588 set = isl_set_coalesce(set);
589 isl_printer_print_set(p, set);
590 isl_printer_end_line(p);
593 isl_set_free(set);
596 /* Consider each fail state in turn as the corresponding
597 * domains may have different dimensions.
599 for (int i = 0; i < msa.fail_state.size(); ++i) {
600 isl_map *acc;
601 isl_set *set;
603 a.set_final(state[msa.fail_state[i]]);
604 rat_exp_t ratexp = aut_to_exp(a);
605 a.clear_final();
607 acc = accessibility(msa, ratexp.value());
608 acc = isl_map_intersect_domain(acc, isl_set_copy(equal_output));
610 set = isl_map_domain(acc);
611 d = isl_set_dim(set, isl_dim_set) / 2;
612 set = isl_set_remove_dims(set, isl_dim_set, d, d);
613 if (!isl_set_is_empty(set)) {
614 ok = 0;
615 isl_printer_print_str(p, "NOT equivalent");
616 isl_printer_end_line(p);
617 set = isl_set_coalesce(set);
618 isl_printer_print_set(p, set);
619 isl_printer_end_line(p);
622 isl_set_free(set);
625 isl_set_free(equal_output);
627 if (!ok)
628 isl_printer_print_str(p, "NOT ");
629 isl_printer_print_str(p, "OK");
630 isl_printer_end_line(p);
632 isl_printer_free(p);
634 return 0;
637 int main(int argc, char *argv[])
639 struct isl_ctx *ctx;
640 struct options *options = eqv2_options_new_with_defaults();
641 isl_set *context = NULL;
642 dependence_graph *dg[2];
644 argc = eqv2_options_parse(options, argc, argv, ISL_ARG_ALL);
646 ctx = isl_ctx_alloc_with_options(&options_args, options);
647 if (!ctx) {
648 fprintf(stderr, "Unable to allocate ctx\n");
649 return -1;
652 if (options->context)
653 context = isl_set_read_from_str(ctx, options->context);
655 pdg::PDG *pdg[2];
656 unsigned out_dim = 0;
657 for (int i = 0; i < 2; ++i) {
658 FILE *in;
659 in = fopen(options->program[i], "r");
660 if (!in) {
661 fprintf(stderr, "Unable to open %s\n", options->program[i]);
662 return -1;
664 pdg[i] = yaml::Load<pdg::PDG>(in, ctx);
665 fclose(in);
666 if (!pdg[i]) {
667 fprintf(stderr, "Unable to read %s\n", options->program[i]);
668 return -1;
670 out_dim = update_out_dim(pdg[i], out_dim);
672 if (context &&
673 pdg[i]->params.size() != isl_set_dim(context, isl_dim_param)) {
674 fprintf(stdout,
675 "Parameter dimension mismatch; context ignored\n");
676 isl_set_free(context);
677 context = NULL;
681 for (int i = 0; i < 2; ++i) {
682 dg[i] = pdg_to_dg(pdg[i], out_dim, isl_set_copy(context));
683 pdg[i]->free();
684 delete pdg[i];
687 int res = check_equivalence(ctx, dg[0], dg[1]);
689 for (int i = 0; i < 2; ++i)
690 delete dg[i];
691 isl_set_free(context);
692 isl_ctx_free(ctx);
694 return res;