PIPS
dag-utils.c
Go to the documentation of this file.
1 /*
2 
3  $Id: dag-utils.c 23495 2018-10-24 09:19:47Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of PIPS.
8 
9  PIPS is free software: you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  PIPS is distributed in the hope that it will be useful, but WITHOUT ANY
15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with PIPS. If not, see <http://www.gnu.org/licenses/>.
22 
23 */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "pips_config.h"
27 #endif
28 
29 #include <stdint.h>
30 #include <stdlib.h>
31 
32 #include "genC.h"
33 #include "misc.h"
34 #include "freia.h"
35 
36 #include "linear.h"
37 #include "pipsdbm.h"
38 
39 #include "ri.h"
40 #include "effects.h"
41 #include "ri-util.h"
42 #include "effects-util.h"
43 #include "properties.h"
44 
45 #include "freia_spoc_private.h"
46 #include "hwac.h"
47 
48 // dirty debug helper...
49 string dagvtx_to_string(const dagvtx v)
50 {
51  return i2a(dagvtx_number(v));
52 }
53 
54 /* return statement if any, or NULL (for input nodes).
55  */
57 {
59  return pstatement_statement_p(ps)? pstatement_statement(ps): NULL;
60 }
61 
62 /* @brief build the set of actual statements in d
63  */
64 void dag_statements(set stats, const dag d)
65 {
66  set_clear(stats);
68  {
70  if (s) set_add_element(stats, stats, s);
71  }
72 }
73 
74 /* a vertex with a non AIPO or image related statement.
75  */
77 {
79 }
80 
81 /* return the produced image or NULL */
83 {
85  return (vtxcontent_out(c) != entity_undefined)? vtxcontent_out(c): NULL;
86 }
87 
88 static void entity_list_dump(FILE * out, const string what, const list l)
89 {
90  fprintf(out, "%s: ", what);
91  FOREACH(entity, e, l)
92  fprintf(out, " %s,", safe_entity_name(e));
93  fprintf(out, "\n");
94 }
95 
96 /* returns the vertex number, i.e. the underlying statement number.
97  */
99 {
100  if (v==NULL) return 0;
102  if (pstatement_statement_p(source))
103  {
104  statement s = pstatement_statement(source);
105  return s? statement_number(s): 0;
106  }
107  else
108  return 0;
109 }
110 
111 string dagvtx_number_str(const dagvtx v)
112 {
113  return i2a(dagvtx_number(v));
114 }
115 
117 {
119 }
120 
122 {
123  return vtxcontent_opid(dagvtx_content(v));
124 }
125 
127 {
128  if (v==NULL) return "null";
129  int index = vtxcontent_opid(dagvtx_content(v));
130  const freia_api_t * api = get_freia_api(index);
131  return api->function_name;
132 }
133 
134 string dagvtx_operation(const dagvtx v)
135 {
136  string op = dagvtx_function_name(v);
137  return strncmp(op, AIPO, strlen(AIPO))==0? op + strlen(AIPO): op;
138 }
139 
141 {
142  if (v==NULL) return "null";
143  int index = vtxcontent_opid(dagvtx_content(v));
144  const freia_api_t * api = get_freia_api(index);
145  return api->compact_name;
146 }
147 
148 int dagvtx_ordering(const dagvtx * v1, const dagvtx * v2)
149 {
150  return dagvtx_number(*v1) - dagvtx_number(*v2);
151 }
152 
153 /* return (last) producer of image e for vertex sink, or NULL if none found.
154  * this is one of the two predecessors of sink.
155  */
156 dagvtx dagvtx_get_producer(const dag d, const dagvtx sink,
157  const entity e, _int before_number)
158 {
159  pips_assert("some image", e!=entity_undefined);
160  FOREACH(dagvtx, v, dag_vertices(d))
161  {
162  vtxcontent c = dagvtx_content(v);
163  pips_debug(8, "%"_intFMT" pred of %"_intFMT"?\n",
164  dagvtx_number(v), dagvtx_number(sink));
165  // they may have been reversed ordered when used to append a vertex
166  if (before_number>0 && dagvtx_number(v)>0 && dagvtx_number(v)>before_number)
167  continue;
168  // the image may be kept within a pipe
169  if (vtxcontent_out(c)==e &&
170  (sink==NULL || gen_in_list_p(sink, dagvtx_succs(v))))
171  return v;
172  }
173  return NULL; // it is an external parameter?
174 }
175 
176 void dagvtx_nb_dump(FILE * out, const string what, const list l)
177 {
178  fprintf(out, "%s: ", what);
179  FOREACH(dagvtx, v, l)
180  fprintf(out, " %" _intFMT ",", dagvtx_number(v));
181  fprintf(out, "\n");
182 }
183 
184 /* for dag debug.
185  */
186 void dagvtx_dump(FILE * out, const string name, const dagvtx v)
187 {
188  if (!v) {
189  fprintf(out, "vertex %s is NULL\n", name? name: "");
190  return;
191  }
192  fprintf(out, "vertex %s %" _intFMT " %s (%p)\n",
193  name? name: "", dagvtx_number(v), dagvtx_operation(v), v);
194  dagvtx_nb_dump(out, " succs", dagvtx_succs(v));
195  vtxcontent c = dagvtx_content(v);
197  fprintf(out,
198  " optype: %s\n"
199  " opid: %" _intFMT "\n"
200  " source: %" _intFMT "/%" _intFMT "\n",
202  vtxcontent_opid(c),
203  s? statement_number(s): 0,
204  s? statement_ordering(s): 0);
205  entity_list_dump(out, " inputs", vtxcontent_inputs(c));
206  fprintf(out, " output: %s\n", safe_entity_name(vtxcontent_out(c)));
207  // to be continued...
208 }
209 
210 /* for dag debug
211  */
212 void dag_dump(FILE * out, const string what, const dag d)
213 {
214  fprintf(out, "dag '%s' (%p) %"_intFMT" vertices:\n",
215  what, d, gen_length(dag_vertices(d)));
216 
217  dagvtx_nb_dump(out, "inputs", dag_inputs(d));
218  dagvtx_nb_dump(out, "outputs", dag_outputs(d));
219  fprintf(out, "\n");
220 
221  FOREACH(dagvtx, vx, dag_vertices(d)) {
222  dagvtx_dump(out, NULL, vx);
223  fprintf(out, "\n");
224  }
225 
226  fprintf(out, "\n");
227 }
228 
229 // #define IMG_DEP " [arrowhead=normal]"
230 #define IMG_DEP ""
231 #define SCL_DEP "arrowhead=empty"
232 
233 static const char* entity_dot_name(entity e)
234 {
235  return entity_user_name(e);
236 }
237 
238 static void dagvtx_dot_node(FILE * out, const string prefix, const dagvtx v)
239 {
240  fprintf(out, "%s\"%"_intFMT" %s\"", prefix? prefix: "",
242 }
243 
244 static void
246 {
247  sb_cat(sb, prefix? prefix: "");
248  sb_cat(sb, "\"", i2a((int) dagvtx_number(v)),
249  " ", dagvtx_compact_operation(v), "\"");
250 }
251 
252 static void dagvtx_dot(FILE * out, const dag d, const dagvtx vtx)
253 {
254  // collect prettyprint properties
255  bool label_nodes = get_bool_property("FREIA_DAG_LABEL_NODES");
256  bool show_arcs = get_bool_property("FREIA_DAG_LABEL_ARCS");
257  bool filter_nodes = get_bool_property("FREIA_DAG_FILTER_NODES");
258 
259  vtxcontent co = dagvtx_content(vtx);
260  const char* vname = NULL;
262  vname = entity_dot_name(vtxcontent_out(co));
263 
264  if (dagvtx_number(vtx)==0)
265  {
266  // this is an input image, only image dependencies
267  FOREACH(dagvtx, succ, dagvtx_succs(vtx))
268  {
269  fprintf(out, " \"%s\"", vname);
270  dagvtx_dot_node(out, " -> ", succ);
271  fprintf(out, ";\n");
272  }
273  }
274  else
275  {
276  // we are dealing with a computation...
277  string attribute = what_operation_shape(vtxcontent_optype(co));
279  bool some_arcs = false;
280 
281  // first check for image dependencies
282  FOREACH(dagvtx, succ, dagvtx_succs(vtx))
283  {
284  dagvtx_dot_node_sb(sa, " ", vtx);
285  dagvtx_dot_node_sb(sa, " -> ", succ);
286  sb_cat(sa, show_arcs? " [label=\"": "",
287  show_arcs? vname: "", show_arcs? "\"]": "", ";\n");
288  some_arcs = true;
289  }
290 
291  // then scalar dependencies anywhere... hmmm...
292  FOREACH(dagvtx, v, dag_vertices(d))
293  {
294  list vars = NIL;
295  if (// another vertex
296  vtx!=v &&
297  // with dependencies
299  dagvtx_statement(v), &vars))
300  {
301  // show scalar dep in sequence order
302  if (dagvtx_number(v)>dagvtx_number(vtx))
303  {
304  dagvtx_dot_node_sb(sa, " ", vtx);
305  dagvtx_dot_node_sb(sa, " -> ", v);
306  }
307  else
308  {
309  dagvtx_dot_node_sb(sa, " ", v);
310  dagvtx_dot_node_sb(sa, " -> ", vtx);
311  }
312 
313  sb_cat(sa, " [" SCL_DEP);
314 
315  if (vars && show_arcs)
316  {
317  int count = 0;
318  sb_cat(sa, ",label=\"");
319  FOREACH(entity, var, vars)
320  sb_cat(sa, count++? " ": "", entity_dot_name(var));
321  sb_cat(sa, "\"");
322  }
323  sb_cat(sa, "];\n");
324 
325  some_arcs = true;
326  }
327  gen_free_list(vars), vars = NIL;
328  }
329 
330  bool some_image_stuff = !dagvtx_other_stuff_p(vtx);
331 
332  if (!filter_nodes || some_image_stuff || (filter_nodes && some_arcs))
333  {
334  // appends the node description
335  dagvtx_dot_node(out, " ", vtx);
336  fprintf(out, " [%s", attribute);
337  if (!label_nodes)
338  // show a short label with only the operation
339  fprintf(out, ",label=\"%s\"", dagvtx_compact_operation(vtx));
340  fprintf(out, "];\n");
341  // now appends arcs...
343  }
344 
345  // cleanup
346  string_buffer_free(&sa);
347  }
348 }
349 
350 static void dagvtx_copy_list_dot(FILE * out, const list ls, const set inputs)
351 {
352  FOREACH(statement, s, ls)
353  {
355  if (c && same_string_p(entity_local_name(call_function(c)), AIPO "copy"))
356  {
357  list args = call_arguments(c);
358  pips_assert("two args to aipo copy", gen_length(args)==2);
361  fprintf(out,
362  " \"%s%s\" [shape=circle];\n"
363  " \"%s =\" [shape=circle,label=\"=\",style=\"dashed\"]\n"
364  " \"%s%s\" -> \"%s =\";\n"
365  " \"%s =\" -> \"%s%s\";\n",
366  entity_dot_name(dst), set_belong_p(inputs, dst)? "'": "",
367  entity_dot_name(dst),
368  entity_dot_name(src), set_belong_p(inputs, src)? "'": "",
369  entity_dot_name(dst), entity_dot_name(dst),
370  entity_dot_name(dst), set_belong_p(inputs, dst)? "'": "");
371  }
372  // should not be a else?
373  }
374 }
375 
376 static void dagvtx_list_dot(
377  FILE * out, const string comment, const list l, const set used)
378 {
379  if (comment) fprintf(out, " // %s\n", comment);
380  FOREACH(dagvtx, v, l)
381  {
383  fprintf(out, " \"%s%s\" [shape=circle];\n",
384  entity_dot_name(img),
385  used? (set_belong_p(used, img)? "'": ""): "");
386  }
387  fprintf(out, "\n");
388 }
389 
390 static bool dagvtx_is_operator_p(const dagvtx v, const string opname)
391 {
392  vtxcontent c = dagvtx_content(v);
393  const freia_api_t * api = get_freia_api(vtxcontent_opid(c));
394  return same_string_p(cat(AIPO, opname), api->function_name);
395 }
396 
397 /* returns whether the vertex is an image copy operation.
398  */
399 static bool dagvtx_is_copy_p(const dagvtx v)
400 {
401  return dagvtx_is_operator_p(v, "copy");
402 }
403 
404 /* @brief output dag in dot format, for debug or show
405  * @param out, append to this file
406  * @param what, name of dag
407  * @param d, dag to output
408  */
409 void dag_dot(FILE * out, const string what, const dag d,
410  const list lb, const list la)
411 {
412  // compute and show dag statistics
413  // count image, copy, scalar operations
414  int niops = 0, ncops = 0, nsops = 0;
415  FOREACH(dagvtx, op, dag_vertices(d))
416  {
417  if (dagvtx_is_copy_p(op)) ncops++;
418  else if (!gen_in_list_p(op, dag_inputs(d))) {
419  if (dagvtx_other_stuff_p(op)) nsops++;
420  else niops++;
421  }
422  }
423 
424  fprintf(out, "// DAG \"%s\": "
425  // input, output, computation, scalar vertices
426  "#i=%d #o=%d #c=%d #s=%d "
427  // copies: internal, before, after
428  "#I=%d #B=%d #A=%d\n",
429  what,
430  (int) gen_length(dag_inputs(d)), (int) gen_length(dag_outputs(d)),
431  niops, nsops, ncops, (int) gen_length(lb), (int) gen_length(la));
432 
433  // start graph
434  fprintf(out, "digraph \"%s\" {\n", what);
435 
436  // collect set of input images
437  set inputs = set_make(set_pointer);
438  FOREACH(dagvtx, i, dag_inputs(d))
439  {
440  entity img = dagvtx_image(i);
441  if (img && img!=entity_undefined)
442  set_add_element(inputs, inputs, img);
443  }
444 
445  // first, declare inputs and outputs as circles
446  dagvtx_list_dot(out, "inputs", dag_inputs(d), NULL);
447  dagvtx_list_dot(out, "outputs", dag_outputs(d), inputs);
448 
449  // second, show computations
450  fprintf(out, " // computation vertices\n");
451  FOREACH(dagvtx, vx, dag_vertices(d))
452  {
453  dagvtx_dot(out, d, vx);
454  vtxcontent c = dagvtx_content(vx);
455 
456  // outputs arcs for vx when the result is extracted
457  if (gen_in_list_p(vx, dag_outputs(d)))
458  {
459  entity img = vtxcontent_out(c);
460  dagvtx_dot_node(out, " ", vx);
461  fprintf(out, " -> \"%s%s\";\n",
462  entity_dot_name(img), set_belong_p(inputs, img)? "'": "");
463  }
464  }
465 
466  // handle external copies after the computation
467  if (lb)
468  {
469  fprintf(out, "\n // external before copies: %d\n", (int) gen_length(lb));
470  dagvtx_copy_list_dot(out, lb, inputs);
471  }
472 
473  if (la)
474  {
475  fprintf(out, "\n // external after copies: %d\n", (int) gen_length(la));
476  dagvtx_copy_list_dot(out, la, inputs);
477  }
478 
479  fprintf(out, "}\n");
480 
481  set_free(inputs);
482 }
483 
484 #define DOT_SUFFIX ".dot"
485 
486 /* generate a "dot" format from a dag to a file.
487  */
488 void dag_dot_dump(const string module, const string name,
489  const dag d, const list lb, const list la)
490 {
491  // build file name
492  string src_dir = db_get_directory_name_for_module(module);
493  string fn = strdup(cat(src_dir, "/", name, DOT_SUFFIX, NULL));
494  free(src_dir);
495 
496  FILE * out = safe_fopen(fn, "w");
497  fprintf(out, "// graph for dag \"%s\" of module \"%s\" in dot format\n",
498  name, module);
499  dag_dot(out, name, d, lb, la);
500  safe_fclose(out, fn);
501  free(fn);
502 }
503 
504 void dag_dot_dump_prefix(const string module, const string prefix, int number,
505  const dag d, const list lb, const list la)
506 {
507  string name = strdup(cat(prefix, i2a(number), NULL));
508  dag_dot_dump(module, name, d, lb, la);
509  free(name);
510 }
511 
512 // debug help
513 static void check_removed(const dagvtx v, const dagvtx removed)
514 {
515  pips_assert("not removed vertex", v!=removed);
516 }
517 
518 static int dagvtx_cmp_entity(const dagvtx * v1, const dagvtx * v2)
519 {
522 }
523 
525 {
527 }
528 
529 /* do some consistency checking...
530  */
532 {
533  FOREACH(dagvtx, v, dag_inputs(d))
534  pips_assert("vertex once in inputs", gen_occurences(v, dag_inputs(d))==1);
535 
536  set variable_seen = set_make(set_pointer);
537  FOREACH(dagvtx, v, dag_inputs(d))
538  {
540  // fprintf(stdout, " - image %s\n", entity_name(image));
541  pips_assert("image is defined", image!=entity_undefined);
542  pips_assert("variable only once in inputs",
543  !set_belong_p(variable_seen, image));
544  set_add_element(variable_seen, variable_seen, image);
545  }
546  set_free(variable_seen);
547 }
548 
549 /* remove unused inputs
550  */
552 {
553  list nl = NIL;
554  FOREACH(dagvtx, v, dag_inputs(d))
555  {
556  if (dagvtx_succs(v)!=NIL) // do we keep it?
557  nl = CONS(dagvtx, v, nl);
558  else
559  gen_remove(&dag_vertices(d), v);
560  // ??? memory leak? there may be "pointers" somewhere to these?
561  // free_dagvtx(v);
562  }
563  if (dag_inputs(d)) gen_free_list(dag_inputs(d));
564  dag_inputs(d) = gen_nreverse(nl);
565 }
566 
567 /* remove vertex v from dag d.
568  * if v isx a used computation vertex, it is substituted by an input vertex.
569  */
570 void dag_remove_vertex(dag d, const dagvtx v)
571 {
572  // hmmm...
573  // pips_assert("vertex is in dag", gen_in_list_p(v, dag_vertices(d)));
574  if (!gen_in_list_p(v, dag_vertices(d)))
575  // already done???
576  return;
577 
578  if (dagvtx_succs(v))
579  {
580  // the ouput of the removed operation becomes an input to the dag
582  pips_assert("some variable", var!=entity_undefined);
583  dagvtx input =
589  }
590 
591  // remove from all vertex lists
592  gen_remove(&dag_vertices(d), v);
593  gen_remove(&dag_inputs(d), v);
594  gen_remove(&dag_outputs(d), v);
595 
596  // remove from successors of any ???
597  FOREACH(dagvtx, dv, dag_vertices(d))
598  gen_remove(&dagvtx_succs(dv), v);
599 
600  // cleanup input list
602 
603  // unlink vertex itself
605 
607 }
608 
609 /* copy a vertex, but without its successors.
610  */
612 {
613  list lsave = dagvtx_succs(v);
614  // temporary cut costs
615  dagvtx_succs(v) = NIL;
616  dagvtx copy = copy_dagvtx(v);
617  dagvtx_succs(v) = lsave;
618  return copy;
619 }
620 
621 /* returns whether the vertex is an image measurement operation.
622  */
624 {
625  vtxcontent c = dagvtx_content(v);
626  const freia_api_t * api = get_freia_api(vtxcontent_opid(c));
627  return strncmp(api->function_name, AIPO "global_", strlen(AIPO "global_"))==0;
628 }
629 
630 /* append new vertex nv to dag d.
631  */
633 {
634  pips_assert("not in dag", !gen_in_list_p(nv, dag_vertices(d)));
635  pips_assert("no successors", dagvtx_succs(nv) == NIL);
636 
637  // pips_assert("dag d ok 1", dag_consistent_p(d));
638  // pips_assert("nv is ok", dagvtx_consistent_p(nv));
639 
641  {
642  pips_assert("e is defined", e!=entity_undefined);
643  dagvtx pv = dagvtx_get_producer(d, NULL, e, dagvtx_number(nv));
644  if (!pv)
645  {
646  // side effect, create an input node of type 0 (not a computation)
647  pv = make_dagvtx
649 
650  dag_inputs(d) = CONS(dagvtx, pv, dag_inputs(d));
652  dag_vertices(d) = CONS(dagvtx, pv, dag_vertices(d));
653  }
654  // a vertex may have several time the same successor: b = a + a
655  dagvtx_succs(pv) = CONS(dagvtx, nv, dagvtx_succs(pv));
656  }
657  dag_vertices(d) = CONS(dagvtx, nv, dag_vertices(d));
658 
659  // ??? what about scalar deps?
660 }
661 
662 /* return the number of actual operations in dag d.
663  * may be zero if only input vertices remain in the dag after optimizations.
664  */
666 {
667  int count = 0;
668  FOREACH(dagvtx, v, dag_vertices(d))
669  if (dagvtx_number(v)!=0)
670  count++;
671  return count;
672 }
673 
674 /* return target predecessor vertices as a list.
675  * the same predecessor appears twice in b = a+a
676  * build them in call order!
677  * ??? maybe I should build a cache for performance,
678  * but I would have to keep track of when dags are modified...
679  */
680 list dag_vertex_preds(const dag d, const dagvtx target)
681 {
682  pips_debug(8, "building predecessors of %"_intFMT"\n", dagvtx_number(target));
683  list inputs = vtxcontent_inputs(dagvtx_content(target));
684  int nins = (int) gen_length(inputs);
685  entity first_img = NULL, second_img = NULL;
686  if (nins>=1) first_img = ENTITY(CAR(inputs));
687  if (nins==2) second_img = ENTITY(CAR(CDR(inputs)));
688  dagvtx first_v = NULL, second_v = NULL;
689 
690  FOREACH(dagvtx, v, dag_vertices(d))
691  {
692  if (v!=target && gen_in_list_p(target, dagvtx_succs(v)))
693  {
694  if (dagvtx_image(v)==first_img)
695  first_v = v;
696  if (dagvtx_image(v)==second_img)
697  second_v = v;
698  }
699  }
700 
701  list preds = NIL;
702  if (second_v) preds = CONS(dagvtx, second_v, NIL);
703  if (first_v) preds = CONS(dagvtx, first_v, preds);
704  return preds;
705 }
706 
707 static bool gen_list_equals_p(const list l1, const list l2)
708 {
709  bool equal = true;
710  list p1 = (list) l1, p2 = (list) l2;
711  while (equal && p1 && p2) {
712  if (CHUNK(CAR(p1))!=CHUNK(CAR(p2)))
713  equal = false;
714  p1 = CDR(p1), p2 = CDR(p2);
715  }
716  equal &= (!p1 && !p2);
717  return equal;
718 }
719 
720 /* replace target measure to a copy of source result...
721  * @param target to be removed/replaced because redundant
722  * @param source to be kept
723  * @return whether the statement is to be actually removed
724  */
725 static bool switch_vertex_to_assign(dagvtx target, dagvtx source)
726 {
727  pips_debug(5, "replacing measure %"_intFMT" by %"_intFMT" result\n",
728  dagvtx_number(target), dagvtx_number(source));
729 
730  // update target vertex
731  vtxcontent cot = dagvtx_content(target);
733  vtxcontent_opid(cot) = hwac_freia_api_index("freia_aipo_scalar_copy");
734  // no more image inputs
736  vtxcontent_inputs(cot) = NIL;
737 
738  // ??? source -> target scalar dependency?
739 
740  // update actual statement.
741  call cref = statement_call(dagvtx_statement(source));
742  expression eref = EXPRESSION(CAR(CDR(call_arguments(cref))));
743  call cnew = statement_call(dagvtx_statement(target));
744  expression enew = EXPRESSION(CAR(CDR(call_arguments(cnew))));
745 
746  if (expression_equal_p(eref, enew))
747  // just remove the fully redundant measure
748  return true;
749 
750  // replace by assign
752 
753  // ??? memory leak or core dump
754  // gen_full_free_list(call_arguments(cnew));
755  // possibly due to effects which are loaded?
756  call_arguments(cnew) =
760  NIL);
761 
762  return false;
763 }
764 
765 /* subtitute produced or used image in the statement of vertex v.
766  * @param v vertex
767  * @param source image variable to replace
768  * @param target new image variable to use
769  * @param used whether to replace used image (input, forward propagation)
770  * or procuded image (output, backward propagation)
771  */
773 (dagvtx v, entity source, entity target, bool used)
774 {
775  pips_debug(8, "image %s -> %s in %"_intFMT"\n",
776  entity_name(source), entity_name(target), dagvtx_number(v));
777 
778  int nsubs=0;
779  vtxcontent vc = dagvtx_content(v);
780  pstatement ps = vtxcontent_source(vc);
781  pips_assert("is a statement", pstatement_statement_p(ps));
782 
783  // get call
785  list args = call_arguments(c);
786 
787  const freia_api_t * api = dagvtx_freia_api(v);
788 
789  // how many argument to skip, how many to replace
790  unsigned int skip, subs;
791 
792  if (used)
793  skip = api->arg_img_out, subs = api->arg_img_in;
794  else
795  skip = 0, subs = api->arg_img_out;
796 
797  pips_assert("call length is okay", gen_length(args)>=skip+subs);
798 
799  while (skip--)
800  args = CDR(args);
801 
802  while (subs--)
803  {
804  expression e = EXPRESSION(CAR(args));
805  // I'm not sure what to do if an image is not a simple reference...
806  pips_assert("image argument is a reference", expression_reference_p(e));
808 
809  if (reference_variable(r)==source)
810  nsubs++, reference_variable(r) = target;
811  args = CDR(args);
812  }
813 
814  // ??? Hmmm... this happens in freia_3muls, not sure why.
815  // pips_assert("some image substitutions", nsubs>0);
816 }
817 
818 /* replace target vertex by a copy of source results...
819  * @param target to be removed
820  * @param source does perform the same computation
821  * @param tpreds target predecessors to be added to source
822  */
823 static void switch_vertex_to_a_copy(dagvtx target, dagvtx source, list tpreds)
824 {
825  pips_debug(5, "replacing %"_intFMT" by %"_intFMT"\n",
826  dagvtx_number(target), dagvtx_number(source));
827 
828  ifdebug(9) {
829  dagvtx_dump(stderr, "in source", source);
830  dagvtx_dump(stderr, "in target", target);
831  }
832 
833  entity src_img = dagvtx_image(source);
834  // fix contents
835  vtxcontent cot = dagvtx_content(target);
839  vtxcontent_inputs(cot) = CONS(entity, src_img, NIL);
840 
841  // fix vertices
842  FOREACH(dagvtx, v, tpreds)
843  gen_remove(&dagvtx_succs(v), target);
844 
845  entity trg_img = dagvtx_image(target);
846  FOREACH(dagvtx, s, dagvtx_succs(target))
847  {
848  gen_list_patch(vtxcontent_inputs(dagvtx_content(s)), trg_img, src_img);
849  // also fix subsequent statements, for AIPO output
850  substitute_image_in_statement(s, trg_img, src_img, true);
851  }
852  dagvtx_succs(source) = gen_once(target, dagvtx_succs(source));
853  dagvtx_succs(source) = gen_nconc(dagvtx_succs(target), dagvtx_succs(source));
854  dagvtx_succs(target) = NIL;
855 
856  // should I kill the statement? no, done by the copy removal stuff
857 
858  ifdebug(9) {
859  dagvtx_dump(stderr, "out source", source);
860  dagvtx_dump(stderr, "out target", target);
861  }
862 }
863 
864 /* @return whether two vertices are the same operation
865  */
866 static bool same_operation_p(const dagvtx v1, const dagvtx v2)
867 {
868  return
869  dagvtx_optype(v1) == dagvtx_optype(v2) &&
870  dagvtx_opid(v1) == dagvtx_opid(v2);
871 }
872 
873 /* @return whether two vertices are commutors
874  */
875 static bool commutative_operation_p(const dagvtx v1, const dagvtx v2)
876 {
877  if (dagvtx_optype(v1) == dagvtx_optype(v2))
878  {
879  int n1 = (int) dagvtx_opid(v1), n2 = (int) dagvtx_opid(v2);
880  const freia_api_t * f1 = get_freia_api(n1);
881  return f1->commutator && hwac_freia_api_index(f1->commutator)==n2;
882  }
883  else return false;
884 }
885 
886 /* @return whether two lists are commuted
887  */
888 static bool list_commuted_p(const list l1, const list l2)
889 {
890  pips_assert("length 2", gen_length(l1)==2 && gen_length(l2)==2);
891  return CHUNKP(CAR(CDR(l1)))==CHUNKP(CAR(l2)) &&
892  CHUNKP(CAR(l1))==CHUNKP(CAR(CDR(l2)));
893 }
894 
895 /* "copy" copies "source" image in dag "d".
896  * remove it properly (forward copy propagation)
897  */
898 static void unlink_copy_vertex(dag d, const entity source, dagvtx copy)
899 {
900  pips_debug(8, "unlinking %"_intFMT"\n", dagvtx_number(copy));
901 
902  entity target = vtxcontent_out(dagvtx_content(copy));
903  // may be NULL if source is an input
904  dagvtx prod = dagvtx_get_producer(d, copy, source, 0);
905 
906  // add copy successors as successors of prod
907  // it is kept as a successor in case it is not removed
908  if (prod)
909  {
910  FOREACH(dagvtx, vs, dagvtx_succs(copy))
911  dagvtx_succs(prod) = gen_once(vs, dagvtx_succs(prod));
912  }
913 
914  // replace use of target image by source image in all v successors
915  FOREACH(dagvtx, succ, dagvtx_succs(copy))
916  {
917  vtxcontent sc = dagvtx_content(succ);
918  gen_list_patch(vtxcontent_inputs(sc), target, source);
919 
920  // also in the statement inputs... (needed for AIPO target)
921  substitute_image_in_statement(succ, target, source, true);
922  }
923 
924  // copy has no more successors
926  dagvtx_succs(copy) = NIL;
927 }
928 
929 /* @return whether all vertices in list "lv" are copies.
930  */
932 {
933  FOREACH(dagvtx, v, lv)
935  return false;
936  return true;
937 }
938 
939 /* @return the number of copies in the vertex list
940  */
941 static int number_of_copies(list /* of dagvtx */ l)
942 {
943  int n=0;
944  FOREACH(dagvtx, v, l)
945  if (dagvtx_is_copy_p(v))
946  n++;
947  return n;
948 }
949 
950 // tell whether this is this (short name) aipo function (static test)?
951 #define aipo_op_p(a, name) \
952  same_string_p(AIPO name, a->function_name)
953 
954 /* @brief compute a constant expression for FREIA
955  * ??? TODO partial eval if values are constant
956  */
957 static expression compute_constant(string op, expression val1, expression val2)
958 {
959  // rough! could/should do some partial evaluation here
961  pips_assert("operator function found", eop!=entity_undefined);
962  call c = make_call(eop,
964  CONS(expression, copy_expression(val2), NIL)));
965  return call_to_expression(c);
966 }
967 
968 /* switch vertex statement to an aipo call
969  * @param v vertex to modify
970  * @param name function short name to switch to, must be an AIPO function
971  * @param img possible image argument, may be entity_undefined or NULL
972  * @param val possible scalar argument, may be expression undefined or NULL
973  */
974 static void set_aipo_call(dagvtx v, string name, entity img, expression val)
975 {
976  vtxcontent c = dagvtx_content(v);
978  pips_assert("some statement!", pstatement_statement_p(ps));
979 
980  // build function name
981  string fname = strdup(cat(AIPO, name));
982 
983  // remove previous image inputs
985  vtxcontent_inputs(c) =
986  (img && img!=entity_undefined)? CONS(entity, img, NIL): NIL;
987 
988  // set id & type
990  pips_assert("function index found", vtxcontent_opid(c)!=-1);
991  vtxcontent_optype(c) =
992  same_string_p(name, "copy")? spoc_type_nop: spoc_type_alu;
993 
994  // set call
997  pips_assert("AIPO function found", func!=entity_undefined);
998  call_function(cf) = func;
999 
1000  // build expression list in reverse order
1001  list args = NIL;
1002  if (val && val!=expression_undefined)
1003  args = CONS(expression, copy_expression(val), args);
1004  if (img && img!=entity_undefined)
1005  args = CONS(expression, entity_to_expression(img), args);
1007  // with a bold memory leak (effects may use refs?)
1008  call_arguments(cf) = args;
1009 
1010  // cleanup
1011  free(fname);
1012 }
1013 
1014 /* @brief switch vertex to a copy of an image
1015  */
1016 static void set_aipo_copy(dagvtx v, entity e)
1017 {
1018  set_aipo_call(v, "copy", e, NULL);
1019 }
1020 
1021 /************************************************************** DAG SIMPLIFY */
1022 
1023 // forward declarations for recursion
1025 static void set_aipo_constant(dagvtx, expression);
1027 static entity copy_image_p(dagvtx);
1028 
1029 /* @brief propagate constant image to vertex successors
1030  */
1032 {
1033  vtxcontent c = dagvtx_content(v);
1034  list nsuccs = NIL;
1035  // i=? -> i+i => to identical successors, but forward once
1037  FOREACH(dagvtx, s, dagvtx_succs(v))
1038  {
1039  if (!set_belong_p(seen, s) &&
1041  nsuccs = CONS(dagvtx, s, nsuccs);
1042  set_add_element(seen, seen, s);
1043  }
1044  set_free(seen);
1045  dagvtx_succs(v) = gen_nreverse(nsuccs);
1046 }
1047 
1048 /* @brief recursively propagate a constant image on a vertex
1049  * @param v starting vertex
1050  * @param image which is constant
1051  * @param val actual value of all image pixels
1052  * @return whether v can be unlinked
1053  * ??? small memory leaks
1054  */
1056 {
1057  vtxcontent c = dagvtx_content(v);
1058  _int op = vtxcontent_opid(c);
1060  if (op<=0) return false;
1061  // op>0
1062  const freia_api_t * api = get_freia_api(op);
1063  int noccs = gen_occurences(image, vtxcontent_inputs(c));
1064  pips_assert("image is used at least once", noccs>0);
1065  int nargs = gen_length(vtxcontent_inputs(c));
1066  bool image_is_first = ENTITY(CAR(vtxcontent_inputs(c)))==image;
1067 
1068  if (copy_image_p(v)!=NULL)
1069  {
1071  set_aipo_copy(v, image);
1072  return false;
1073  }
1074 
1075  if (noccs==1 && nargs==1) // Cst(n)<op>.m => Cst(n<op>m)
1076  {
1077  string op = NULL;
1078  if (aipo_op_p(api, "add_const")) op = "+";
1079  else if (aipo_op_p(api, "sub_const")) op = "-";
1080  else if (aipo_op_p(api, "mul_const")) op = "*";
1081  else if (aipo_op_p(api, "div_const")) op = "/";
1082  else if (aipo_op_p(api, "and_const")) op = BITWISE_AND_OPERATOR_NAME;
1083  else if (aipo_op_p(api, "or_const")) op = "|";
1084  else if (aipo_op_p(api, "xor_const")) op = BITWISE_XOR_OPERATOR_NAME;
1085  // ??? TODO addsat, subsat, inf, sup, not, log2...
1086  // but I need the corresponding scalar functions
1087  // some of which depends on the actual pixel type
1088  else if (aipo_op_p(api, "erode_6c") || aipo_op_p(api, "dilate_6c") ||
1089  aipo_op_p(api, "erode_8c") || aipo_op_p(api, "dilate_8c"))
1090  newval = val;
1091  // ??? TODO threshold
1092  // ??? TODO global_min/global_max can be switch to a simple assign
1093  // ??? TODO global_vol can be switched to n_pixels*val
1094 
1095  if (op)
1096  newval = compute_constant(op, val, freia_get_nth_scalar_param(v, 1));
1097  if (newval!=expression_undefined)
1098  {
1099  set_aipo_constant(v, newval);
1100  return true;
1101  }
1102  }
1103  else if (noccs==1 && nargs==2)
1104  {
1105  string op = NULL;
1106  entity other = image_is_first?
1108 
1109  if (aipo_op_p(api, "add")) op = "add_const";
1110  else if (aipo_op_p(api, "mul")) op = "mul_const";
1111  else if (aipo_op_p(api, "and")) op = "add_const";
1112  else if (aipo_op_p(api, "or")) op = "or_const";
1113  else if (aipo_op_p(api, "xor")) op = "xor_const";
1114  else if (aipo_op_p(api, "inf")) op = "inf_const";
1115  else if (aipo_op_p(api, "sup")) op = "sup_const";
1116  else if (aipo_op_p(api, "addsat")) op = "addsat_const";
1117  else if (aipo_op_p(api, "subsat")) op = "subsat_const";
1118  else if (aipo_op_p(api, "absdiff")) op = "absdiff_const";
1119  else if (aipo_op_p(api, "sub"))
1120  op = image_is_first? "const_sub": "sub_const";
1121  else if (aipo_op_p(api, "div"))
1122  op = image_is_first? "const_div": "div_const";
1123 
1124  if (op)
1125  {
1126  set_aipo_call(v, op, other, val);
1127  return true;
1128  }
1129  }
1130  else if (noccs==2)
1131  {
1132  // special case for (image <op> image)
1133  if (aipo_op_p(api, "add"))
1134  {
1136  return true;
1137  }
1138  else if (aipo_op_p(api, "sub"))
1139  {
1141  return true;
1142  }
1143  }
1144  return false;
1145 }
1146 
1147 /* @brief set vertex as a constant image and propagate to successors
1148  */
1150 {
1151  set_aipo_call(v, "set_constant", entity_undefined, val);
1153 }
1154 
1155 /* @brief whether vertex generates a constant image
1156  * @param v vertex to consider
1157  * @return constant allocated expression or NULL
1158  */
1160 {
1161  vtxcontent c = dagvtx_content(v);
1162  _int op = vtxcontent_opid(c);
1163  const freia_api_t * api = get_freia_api(op);
1164  if (api->arg_img_in==2)
1165  {
1166  pips_assert("2 input images", gen_length(vtxcontent_inputs(c))==2);
1167  entity e1 = ENTITY(CAR(vtxcontent_inputs(c))),
1168  e2 = ENTITY(CAR(CDR(vtxcontent_inputs(c))));
1169  if (e1==e2 && (aipo_op_p(api, "sub") || aipo_op_p(api, "xor")))
1170  return int_to_expression(0);
1171  if (e1==e2 && aipo_op_p(api, "div"))
1172  return int_to_expression(1);
1173  }
1174  else if (api->arg_img_in==1)
1175  {
1176  bool
1177  erosion = aipo_op_p(api, "erode_8c") || aipo_op_p(api, "erode_6c"),
1178  dilatation = aipo_op_p(api, "dilate_8c") || aipo_op_p(api, "dilate_6c");
1179  // aipo_op_p(api, "convolution") 3x3?
1180  if (erosion || dilatation)
1181  {
1182  _int i00, i10, i20, i01, i11, i21, i02, i12, i22;
1183  if (freia_extract_kernel_vtx(v, true, &i00, &i10, &i20,
1184  &i01, &i11, &i21, &i02, &i12, &i22))
1185  {
1186  // zero boundary
1187  if (i00==0 && i10==0 && i20==0 && i01==0 &&
1188  i21==0 && i02==0 && i12==0 && i22==0)
1189  {
1190  if (i11==0)
1191  {
1192  if (erosion)
1193  return int_to_expression(0);
1194  else if (dilatation)
1196  }
1197  }
1198  }
1199  }
1200  else if (api->arg_misc_in==1) // arith cst op
1201  {
1203  _int val;
1204  if (expression_integer_value(e1, &val))
1205  {
1206  if ((aipo_op_p(api, "mul_const") && val==0) ||
1207  (aipo_op_p(api, "and_const") && val==0) ||
1208  (aipo_op_p(api, "inf_const") && val==0) ||
1209  (aipo_op_p(api, "const_div") && val==0))
1210  return int_to_expression(val);
1211 
1212  int maxval = freia_max_pixel_value();
1213  if ((aipo_op_p(api, "sup_const") && val==maxval) ||
1214  (aipo_op_p(api, "or_const") && val==maxval) ||
1215  (aipo_op_p(api, "addsat_const") && val==maxval))
1216  return int_to_expression(val);
1217 
1218  if ((aipo_op_p(api, "subsat_const") && val==maxval))
1219  return int_to_expression(0);
1220  }
1221  }
1222  }
1223  else if (api->arg_img_in==0)
1224  {
1225  if (aipo_op_p(api, "set_constant"))
1227  }
1228  return NULL;
1229 }
1230 
1231 /* @brief tell whether vertex can be assimilated to a copy
1232  * e.g. i+.0 i*.1 i/.1 i|.0 i-.0 i&i i|i i>i i<i
1233  * @return image to copy, or NULL
1234  */
1236 {
1237  vtxcontent c = dagvtx_content(v);
1238  _int op = vtxcontent_opid(c);
1239  const freia_api_t * api = get_freia_api(op);
1240  if (api->arg_img_in==2)
1241  {
1242  pips_assert("2 input images", gen_length(vtxcontent_inputs(c))==2);
1243  entity e1 = ENTITY(CAR(vtxcontent_inputs(c))),
1244  e2 = ENTITY(CAR(CDR(vtxcontent_inputs(c))));
1245  if (e1==e2 && (aipo_op_p(api, "and") ||
1246  aipo_op_p(api, "or") ||
1247  aipo_op_p(api, "sup") ||
1248  aipo_op_p(api, "inf")))
1249  return e1;
1250  }
1251  else if (api->arg_img_in==1)
1252  {
1253  if (aipo_op_p(api, "erode_8c") ||
1254  aipo_op_p(api, "erode_6c") ||
1255  aipo_op_p(api, "dilate_8c") ||
1256  aipo_op_p(api, "dilate_6c"))
1257  // aipo_op_p(api, "convolution") 3x3?
1258  {
1259  _int i00, i10, i20, i01, i11, i21, i02, i12, i22;
1260  if (freia_extract_kernel_vtx(v, true, &i00, &i10, &i20,
1261  &i01, &i11, &i21, &i02, &i12, &i22))
1262  {
1263  // zero boundary
1264  if (i00==0 && i10==0 && i20==0 && i01==0 &&
1265  i21==0 && i02==0 && i12==0 && i22==0)
1266  {
1267  if (i11==1) return ENTITY(CAR(vtxcontent_inputs(c)));
1268  }
1269  }
1270  }
1271  else if (api->arg_misc_in==1)
1272  {
1274  _int val;
1275  if (expression_integer_value(e1, &val))
1276  {
1277  if ((aipo_op_p(api, "mul_const") && val==1) ||
1278  (aipo_op_p(api, "div_const") && val==1) ||
1279  (aipo_op_p(api, "or_const") && val==0) ||
1280  (aipo_op_p(api, "add_const") && val==0) ||
1281  (aipo_op_p(api, "sub_const") && val==0) ||
1282  (aipo_op_p(api, "sup_const") && val==0))
1283  return ENTITY(CAR(vtxcontent_inputs(c)));
1284 
1285  int maxval = freia_max_pixel_value();
1286  if ((aipo_op_p(api, "inf_const") && val==maxval) ||
1287  (aipo_op_p(api, "addsat") && val==maxval))
1288  return ENTITY(CAR(vtxcontent_inputs(c)));
1289  }
1290  }
1291  else if (api->arg_misc_in==0)
1292  {
1293  if (aipo_op_p(api, "copy"))
1294  return ENTITY(CAR(vtxcontent_inputs(c)));
1295  }
1296  }
1297  return NULL;
1298 }
1299 
1300 /* @brief apply basic algebraic simplification to dag
1301  */
1302 static bool dag_simplify(dag d)
1303 {
1304  bool changed = false;
1305 
1306  // propagate constants and detect copies
1307  FOREACH(dagvtx, v, dag_vertices(d))
1308  {
1309  expression val;
1310  entity img;
1311  if ((val=constant_image_p(v))!=NULL)
1312  {
1313  changed = true;
1314 
1315  // fix successors of predecessors of new "constant" operation
1316  list preds = dag_vertex_preds(d, v);
1317  FOREACH(dagvtx, p, preds)
1318  gen_remove(&dagvtx_succs(p), v);
1319  gen_free_list(preds);
1320 
1321  // swich operation to constant
1322  set_aipo_constant(v, val);
1323  free_expression(val);
1324  }
1325  else if ((img=copy_image_p(v))!=NULL)
1326  {
1327  changed = true;
1328  set_aipo_copy(v, img);
1329  }
1330  // another one just for fun: I+I -> 2*I
1331  // this is good for SPoC
1332  else if (dagvtx_is_operator_p(v, "add"))
1333  {
1334  list preds = dag_vertex_preds(d, v);
1335  pips_assert("two args to add", gen_length(preds)==2);
1336  if (DAGVTX(CAR(preds))==DAGVTX(CAR(CDR(preds))))
1337  {
1338  changed = true;
1339  set_aipo_call(v, "mul_const",
1340  dagvtx_image(DAGVTX(CAR(preds))), int_to_expression(2));
1341  }
1342  }
1343  }
1344 
1345  return changed;
1346 }
1347 
1348 /* normalize, that is use less image operators
1349  * only transformation is: sub_const(i, v) -> add_const(i, -v)
1350  */
1351 static bool dag_normalize(dag d)
1352 {
1353  bool changed = false;
1354  FOREACH(dagvtx, v, dag_vertices(d))
1355  {
1356  vtxcontent ct = dagvtx_content(v);
1357  statement s = dagvtx_statement(v);
1358  call c = s? freia_statement_to_call(s): NULL;
1359  if (c)
1360  {
1361  list args = call_arguments(c);
1362  entity func = call_function(c);
1363  if (same_string_p(entity_local_name(func), AIPO "sub_const"))
1364  {
1365  changed = true;
1366  // sub_const -> add_const(opposite)
1367  // does it always make sense for unsigned pixels?
1368  vtxcontent_opid(ct) = hwac_freia_api_index(AIPO "add_const");
1370  list l3 = CDR(CDR(args));
1371  _int v;
1372  if (expression_integer_value(EXPRESSION(CAR(l3)), &v))
1373  {
1374  // partial eval
1376  EXPRESSION_(CAR(l3)) = int_to_expression(-v);
1377  }
1378  else
1379  {
1380  // symbolic
1381  EXPRESSION_(CAR(l3)) =
1382  MakeUnaryCall(
1384  EXPRESSION(CAR(l3)));
1385  }
1386  }
1387  // what else?
1388  }
1389  }
1390  return changed;
1391 }
1392 
1393 /* @return 0 keep both, 1 keep first, 2 keep second
1394  */
1395 static int compatible_reduction_operation(const dagvtx v1, const dagvtx v2)
1396 {
1397  const string
1398  o1 = dagvtx_compact_operation(v1),
1399  o2 = dagvtx_compact_operation(v2);
1400  if ((same_string_p(o1, "max!") && same_string_p(o2, "max")) ||
1401  (same_string_p(o1, "min!") && same_string_p(o2, "min")))
1402  return 1;
1403  else if ((same_string_p(o1, "max") && same_string_p(o2, "max!")) ||
1404  (same_string_p(o1, "min") && same_string_p(o2, "min!")))
1405  return 2;
1406  else
1407  return 0;
1408 }
1409 
1410 /* remove dead image operations.
1411  * remove AIPO copies detected as useless.
1412  * remove identical operations.
1413  * return list of statements to be managed outside (external copies)...
1414  * ??? maybe there should be a transitive closure...
1415  */
1417  dag d, hash_table exchanges,
1418  list * lbefore, list * lafter)
1419 {
1420  set remove = set_make(set_pointer);
1421  size_t dag_output_count = gen_length(dag_outputs(d));
1422 
1423  ifdebug(6) {
1424  pips_debug(6, "considering dag:\n");
1425  dag_dump(stderr, "input", d);
1426  }
1427 
1428  if (get_bool_property("FREIA_NORMALIZE_OPERATIONS"))
1429  {
1430  dag_normalize(d);
1431 
1432  ifdebug(8) {
1433  pips_debug(4, "after FREIA_NORMALIZE_OPERATIONS:\n");
1434  dag_dump(stderr, "normalized", d);
1435  }
1436  }
1437 
1438  // algebraic simplifications
1439  // currently constant images are detected and propagated and constant pixels
1440  if (get_bool_property("FREIA_SIMPLIFY_OPERATIONS"))
1441  {
1442  dag_simplify(d);
1443 
1444  ifdebug(8) {
1445  pips_debug(4, "after FREIA_SIMPLIFY_OPERATIONS (1):\n");
1446  dag_dump(stderr, "simplified_1", d);
1447  // dag_dot_dump_prefix("main", "simplified", 0, d);
1448  }
1449  }
1450 
1451  // look for identical image operations (same inputs, same params)
1452  // (that produce image, we do not care about measures for SPOC,
1453  // but we should for terapix!)
1454  // the second one is replaced by a copy.
1455  // also handle commutations.
1456  if (get_bool_property("FREIA_REMOVE_DUPLICATE_OPERATIONS"))
1457  {
1458  pips_debug(6, "removing duplicate operations\n");
1459 
1460  // all vertices in dependence order
1461  list vertices = gen_nreverse(gen_copy_seq(dag_vertices(d)));
1462 
1463  // for all already processed vertices, the list of their predecessors
1464  hash_table previous = hash_table_make(hash_pointer, 10);
1465 
1466  // subset of vertices to be investigated
1467  set candidates = set_make(set_pointer);
1468 
1469  // subset of vertices already encountered which do not have predecessors
1470  set sources = set_make(set_pointer);
1471 
1472  // already processed vertices
1473  set processed = set_make(set_pointer);
1474 
1475  // potential n^2 loop, optimized by comparing only to the already processed
1476  // successors of the vertex predecessors . See "candidates" computation.
1477  FOREACH(dagvtx, vr, vertices)
1478  {
1479  int op = (int) vtxcontent_optype(dagvtx_content(vr));
1480  pips_debug(7, "at vertex %"_intFMT" (op=%d)\n", dagvtx_number(vr), op);
1481 
1482  // skip no-operations
1483  if (op<spoc_type_poc || op>spoc_type_mes) continue;
1484 
1485  // skip already removed ops
1486  if (set_belong_p(remove, vr)) continue;
1487 
1488  // pips_debug(8, "investigating...\n");
1489  list preds = dag_vertex_preds(d, vr);
1490 
1491  // build only "interesting" vertices, which shared inputs
1492  set_clear(candidates);
1493 
1494  // successors of predecessors
1495  FOREACH(dagvtx, p, preds)
1496  set_append_list(candidates, dagvtx_succs(p));
1497 
1498  // keep only already processed vertices
1499  set_intersection(candidates, candidates, processed);
1500 
1501  // possibly add those without predecessors (is that only set_const?)
1502  if (!preds) set_union(candidates, candidates, sources);
1503 
1504  // whether the vertex was changed
1505  bool switched = false;
1506 
1507  // I do not need to sort them, they are all different, only one can match
1508  SET_FOREACH(dagvtx, p, candidates)
1509  {
1510  pips_debug(8, "comparing %"_intFMT" and %"_intFMT"\n",
1511  dagvtx_number(vr), dagvtx_number(p));
1512 
1513  list lp = hash_get(previous, p);
1514 
1515  // ??? maybe I should not remove all duplicates, because
1516  // recomputing them may be cheaper?
1518  {
1519  // special handling for measures, esp for terapix
1520  if (gen_list_equals_p(preds, lp))
1521  {
1522  if (same_operation_p(vr, p))
1523  {
1524  // min(A, px), min(A, py) => min(A, px) && *py = *px
1525  if (switch_vertex_to_assign(vr, p))
1526  set_add_element(remove, remove, vr);
1527  // only one can match!
1528  switched = true;
1529  break;
1530  }
1531  else
1532  {
1533  int n = compatible_reduction_operation(p, vr);
1534  if (n==2)
1535  {
1536  // exchange role of vr & p
1537  set_del_element(processed, processed, p);
1538  set_add_element(processed, processed, vr);
1539  hash_del(previous, p);
1540  hash_put(previous, vr, lp);
1541  dagvtx t = p; p = vr; vr = t;
1542  // also in the list of statements to fix dependencies!
1543  if (exchanges) hash_put(exchanges, p, vr);
1544  }
1545  if (n==1 || n==2)
1546  {
1547  // we keep p which is a !, and vr is a simple reduction
1548  if (switch_vertex_to_assign(vr, p))
1549  set_add_element(remove, remove, vr);
1550 
1551  // done
1552  switched = true;
1553  break;
1554  }
1555  }
1556  }
1557  }
1558  else if (same_operation_p(vr, p) &&
1559  gen_list_equals_p(preds, lp) &&
1560  same_constant_parameters(vr, p))
1561  {
1562  switch_vertex_to_a_copy(vr, p, preds);
1563  // only one can match!
1564  switched = true;
1565  break;
1566  }
1567  else if (commutative_operation_p(vr, p) &&
1568  list_commuted_p(preds, (list) lp))
1569  {
1570  switch_vertex_to_a_copy(vr, p, preds);
1571  // only one can match!
1572  switched = true;
1573  break;
1574  }
1575  }
1576 
1577  if (switched)
1578  gen_free_list(preds);
1579  else
1580  {
1581  // update map & sets
1582  hash_put(previous, vr, preds);
1583  set_add_element(processed, processed, vr);
1584  if (!preds) set_add_element(sources, sources, vr);
1585  }
1586  }
1587 
1588  // cleanup
1589  HASH_MAP(k, v, if (v) gen_free_list(v), previous);
1590  hash_table_free(previous), previous = NULL;
1591  gen_free_list(vertices), vertices = NULL;
1592  set_free(candidates);
1593  set_free(sources);
1594  set_free(processed);
1595 
1596  ifdebug(8) {
1597  pips_debug(4, "after FREIA_REMOVE_DUPLICATE_OPERATIONS:\n");
1598  dag_dump(stderr, "remove duplicate", d);
1599  // dag_dot_dump_prefix("main", "remove_duplicates", 0, d);
1600  }
1601  }
1602 
1603  // algebraic simplifications *AGAIN*
1604  // some duplicate operation removal may have enabled more simplifications
1605  // for instance -(a,b) & a=~b => -(a,a) => cst(0)
1606  // we may have a convergence loop on both duplicate/simplify
1607  if (get_bool_property("FREIA_SIMPLIFY_OPERATIONS"))
1608  {
1609  dag_simplify(d);
1610 
1611  ifdebug(8) {
1612  pips_debug(4, "after FREIA_SIMPLIFY_OPERATIONS (2):\n");
1613  dag_dump(stderr, "simplified_2", d);
1614  // dag_dot_dump_prefix("main", "simplified", 0, d);
1615  }
1616  }
1617 
1618  // remove dead image operations
1619  // ??? hmmm... measures are kept because of the implicit scalar dependency?
1620  if (get_bool_property("FREIA_REMOVE_DEAD_OPERATIONS"))
1621  {
1622  pips_debug(6, "removing dead code\n");
1623  list vertices = gen_copy_seq(dag_vertices(d));
1624  FOREACH(dagvtx, v, vertices)
1625  {
1626  // skip non-image operations
1627  if (!vtxcontent_inputs(dagvtx_content(v)) &&
1629  vtxcontent_out(dagvtx_content(v))==NULL))
1630  continue;
1631 
1632  if (// no successors or they are all removed
1633  (!dagvtx_succs(v) || list_in_set_p(dagvtx_succs(v), remove)) &&
1634  // but we keep output nodes...
1635  !gen_in_list_p(v, dag_outputs(d)) &&
1636  // and measures...
1638  {
1639  pips_debug(7, "vertex %"_intFMT" is dead\n", dagvtx_number(v));
1640  set_add_element(remove, remove, v);
1641  }
1642  else
1643  pips_debug(8, "vertex %"_intFMT" is alive\n", dagvtx_number(v));
1644  }
1645  gen_free_list(vertices), vertices = NULL;
1646 
1647  ifdebug(8) {
1648  pips_debug(4, "after FREIA_REMOVE_DEAD_OPERATIONS:\n");
1649  dag_dump(stderr, "remove dead", d);
1650  // dag_dot_dump_prefix("main", "remove_dead", 0, d);
1651  }
1652  }
1653 
1654  if (get_bool_property("FREIA_REMOVE_USELESS_COPIES"))
1655  {
1656  set forwards = set_make(set_pointer);
1657  bool changed = true;
1658 
1659  // I -copy-> X -> ... where I is an input is moved forward
1660  // beware that image identifiers should not be reused, otherwise it may
1661  // merge two arcs... (freia_82 & freia_83)
1662 
1663  // we iterate the hard way, it could be little more subtle
1664  // this is necessary, see copy_02
1665  while (changed)
1666  {
1667  changed = false;
1668 
1669  // first propagate input images through copies
1670  FOREACH(dagvtx, v, dag_inputs(d))
1671  {
1672  list append = NIL;
1674 
1675  FOREACH(dagvtx, s, dagvtx_succs(v))
1676  {
1678  if (dagvtx_is_copy_p(s))
1679  {
1680  // forward propagation in dag & statements
1681  FOREACH(dagvtx, s2, dagvtx_succs(s))
1682  {
1683  substitute_image_in_statement(s2, copy, in, true);
1685  copy, in);
1686  }
1687  // update succs
1689  dagvtx_succs(s) = NIL;
1690 
1691  set_add_element(forwards, forwards, s);
1692  }
1693  }
1694  if (append)
1695  {
1696  FOREACH(dagvtx, a, append)
1697  {
1698  if (!gen_in_list_p(a, dagvtx_succs(v)))
1699  {
1700  dagvtx_succs(v) = CONS(dagvtx, a, dagvtx_succs(v));
1701  changed = true;
1702  }
1703  }
1704  }
1705  }
1706  }
1707 
1708  // op -> X -copy-> A where A is an output is moved backwards
1709  FOREACH(dagvtx, v, dag_vertices(d))
1710  {
1711  // skip special input nodes
1712  if (dagvtx_number(v)==0) continue;
1713 
1714  // skip already removed ops
1715  if (set_belong_p(remove, v)) continue;
1716 
1717  // skip forward propagated inputs
1718  if (set_belong_p(forwards, v)) continue;
1719 
1720  if (dagvtx_is_copy_p(v))
1721  {
1722  list preds = dag_vertex_preds(d, v);
1723  vtxcontent c = dagvtx_content(v);
1724  entity res = vtxcontent_out(c);
1725  pips_assert("one output and one input to copy",
1726  res!=entity_undefined &&
1727  gen_length(preds)==1 &&
1728  gen_length(vtxcontent_inputs(c))==1);
1729 
1730  // first check for A->copy->A really useless copies, which are skipped
1731  entity inimg = ENTITY(CAR(vtxcontent_inputs(c)));
1732  if (inimg==res)
1733  {
1734  set_add_element(remove, remove, v);
1735  dagvtx pred = DAGVTX(CAR(preds));
1736  // update predecessor's successors
1737  gen_remove(&dagvtx_succs(pred), v);
1738  dagvtx_succs(pred) = gen_nconc(dagvtx_succs(pred), dagvtx_succs(v));
1739  // fix global output if necessary
1740  if (gen_in_list_p(v, dag_outputs(d)))
1741  gen_replace_in_list(dag_outputs(d), v, pred);
1742  }
1743  // check for internal-t -one-copy-and-others-> A (output)
1744  // could be improved by dealing with the first copy only?
1745  else if (gen_in_list_p(v, dag_outputs(d)))
1746  {
1747  pips_assert("one predecessor to used copy", gen_length(preds)==1);
1748  dagvtx pred = DAGVTX(CAR(preds));
1749 
1750  if (number_of_copies(dagvtx_succs(pred))==1 &&
1751  !gen_in_list_p(pred, dag_outputs(d)) &&
1752  dagvtx_number(pred)!=0)
1753  {
1754  // BACKWARD COPY PROPAGATION
1755  // that is we want to produce the result directly
1756 
1757  vtxcontent pc = dagvtx_content(pred);
1758  entity old = vtxcontent_out(pc);
1759 
1760  // fix statement, needed for AIPO target
1761  substitute_image_in_statement(pred, old, res, false);
1762 
1763  // fix vertex
1764  vtxcontent_out(pc) = res;
1765  gen_remove(& dagvtx_succs(pred), v);
1766  bool done = gen_replace_in_list(dag_outputs(d), v, pred);
1767  pips_assert("output node was replaced", done);
1768  set_add_element(remove, remove, v);
1769 
1770  // BACK-FORWARD COPY PROPAGATION
1771  FOREACH(dagvtx, s, dagvtx_succs(pred))
1772  {
1773  substitute_image_in_statement(s, old, res, true);
1775  old, res);
1776  }
1777  }
1778  gen_free_list(preds);
1779  }
1780  }
1781  }
1782 
1783  // only one pass is needed because we're going backwards?
1784  // op-> X -copy-> Y images copies are replaced by op-> X & Y
1785  FOREACH(dagvtx, v, dag_vertices(d))
1786  {
1787  // skip special input nodes
1788  if (dagvtx_number(v)==0) continue;
1789 
1790  // skip already removed ops
1791  if (set_belong_p(remove, v)) continue;
1792 
1793  if (dagvtx_is_copy_p(v))
1794  {
1795  vtxcontent c = dagvtx_content(v);
1796  entity target = vtxcontent_out(c);
1797  pips_assert("one output and one input to copy",
1798  target!=entity_undefined && gen_length(vtxcontent_inputs(c))==1);
1799 
1800  // FORWARD COPY PROPAGATION
1801  // replace by its source everywhere it is used
1802  entity source = ENTITY(CAR(vtxcontent_inputs(c)));
1803 
1804  // remove!
1805  unlink_copy_vertex(d, source, v);
1806 
1807  // whether to actually remove v
1808  if (!gen_in_list_p(v, dag_outputs(d)))
1809  set_add_element(remove, remove, v);
1810  }
1811  }
1812 
1813  set_free(forwards);
1814 
1815  ifdebug(8) {
1816  pips_debug(4, "after FREIA_REMOVE_USELESS_COPIES:\n");
1817  dag_dump(stderr, "remove useless copies", d);
1818  // dag_dot_dump_prefix("main", "useless_copies", 0, d);
1819  }
1820  }
1821 
1822  if (get_bool_property("FREIA_MOVE_DIRECT_COPIES"))
1823  {
1824  // A-copy->B where A is an input is removed from the dag and managed outside
1825  // idem A-copy->B where A is an output
1826 
1827  // if A-copy->X and A-copy->Y where A is not an input, the second copy
1828  // is replaced by an external X-copy->Y
1829 
1830  // ??? BUG: it should be moved after the computation
1831 
1832  // what copies are kept in the dag
1833  hash_table intra_pipe_copies = hash_table_make(hash_pointer, 10);
1834 
1835  FOREACH(dagvtx, w, dag_vertices(d))
1836  {
1837  // skip already to-remove nodes
1838  if (set_belong_p(remove, w))
1839  continue;
1840 
1841  if (dagvtx_is_copy_p(w))
1842  {
1843  vtxcontent c = dagvtx_content(w);
1844  entity target = vtxcontent_out(c);
1845  pips_assert("one output and one input to copy",
1846  target!=entity_undefined && gen_length(vtxcontent_inputs(c))==1);
1847 
1848  entity source = ENTITY(CAR(vtxcontent_inputs(c)));
1849  dagvtx prod = dagvtx_get_producer(d, w, source, 0);
1850 
1851  if (source==target)
1852  {
1853  // A->copy->A??? this should not happen?
1854  set_add_element(remove, remove, w);
1855  }
1856  else if (dagvtx_number(prod)==0)
1857  {
1858  // producer is an input
1859  // fprintf(stderr, "COPY 1 removing %"_intFMT"\n", dagvtx_number(w));
1860  unlink_copy_vertex(d, source, w);
1861  set_add_element(remove, remove, w);
1862  *lbefore =
1863  CONS(statement, freia_copy_image(source, target), *lbefore);
1864  }
1865  else if (gen_in_list_p(prod, dag_outputs(d)))
1866  {
1867  // the producer is an output, which can be copied outside...
1868  // well, it may happen that the copy could be performed by the
1869  // accelerator for free, eg for SPoC one output link would happen
1870  // to be available... so we may really add an operation when
1871  // extracting it. However, this should not be an accelerator call?
1872  unlink_copy_vertex(d, source, w);
1873  set_add_element(remove, remove, w);
1874  *lafter = CONS(statement, freia_copy_image(source, target), *lafter);
1875  }
1876  else // source not an input, but the result of an internal computation
1877  {
1879  {
1880  // ??? hmmm... there is an implicit assumption here that the
1881  // source of the copy will be an output...
1882  unlink_copy_vertex(d, source, w);
1883  set_add_element(remove, remove, w);
1884  *lafter =
1885  CONS(statement, freia_copy_image(source, target), *lafter);
1886  }
1887  else if (hash_defined_p(intra_pipe_copies, source))
1888  {
1889  // the source is already copied
1890  unlink_copy_vertex(d, source, w);
1891  set_add_element(remove, remove, w);
1892  *lafter = CONS(statement,
1893  freia_copy_image((entity) hash_get(intra_pipe_copies, source),
1894  target), *lafter);
1895  }
1896  else // keep first copy
1897  hash_put(intra_pipe_copies, source, target);
1898  }
1899  }
1900  }
1901  hash_table_free(intra_pipe_copies);
1902 
1903  ifdebug(8) {
1904  pips_debug(4, "after FREIA_MOVE_DIRECT_COPIES:\n");
1905  dag_dump(stderr, "move direct copies", d);
1906  // dag_dot_dump_prefix("main", "direct_copies", 0, d);
1907  }
1908  }
1909 
1910  // cleanup dag (argh, beware that the order is not deterministic...)
1911  SET_FOREACH(dagvtx, r, remove)
1912  {
1913  pips_debug(7, "removing vertex %" _intFMT "\n", dagvtx_number(r));
1914 
1915  vtxcontent c = dagvtx_content(r);
1918  dag_remove_vertex(d, r);
1919 
1920  ifdebug(8)
1922 
1923  free_dagvtx(r);
1924  }
1925 
1926  set_free(remove);
1927 
1928  // further check for unused input nodes
1929  // this seems needed because some non determinism in the above cleanup.
1930  list vertices = gen_copy_seq(dag_vertices(d));
1931  FOREACH(dagvtx, v, vertices)
1932  {
1933  if (dagvtx_number(v)==0 && !dagvtx_succs(v))
1934  {
1935  dag_remove_vertex(d, v);
1936  free_dagvtx(v);
1937  }
1938  }
1939  gen_free_list(vertices);
1940 
1941  // show result
1942  ifdebug(6) {
1943  pips_debug(4, "resulting dag:\n");
1944  dag_dump(stderr, "cleaned", d);
1945  // dag_dot_dump_prefix("main", "cleaned", 0, d);
1946  }
1947 
1948  // former output images are either still computed or copies of computed
1949  size_t recount = gen_length(dag_outputs(d)) +
1950  gen_length(*lbefore) + gen_length(*lafter);
1951  pips_assert("right output count after dag optimizations",
1952  dag_output_count==recount);
1953 }
1954 
1955 /* return whether all vertices in list are mesures...
1956  */
1957 static bool all_mesures_p(list lv)
1958 {
1959  bool only_mes = true;
1960  FOREACH(dagvtx, v, lv)
1961  {
1962  if (dagvtx_optype(v)!=spoc_type_mes)
1963  {
1964  only_mes = false;
1965  break;
1966  }
1967  }
1968  return only_mes;
1969 }
1970 
1971 /* @return the set of all statements in dag
1972  */
1973 static set dag_stats(dag d)
1974 {
1975  set stats = set_make(set_pointer);
1976  statement s;
1977  FOREACH(dagvtx, v, dag_vertices(d))
1978  if ((s = dagvtx_statement(v)))
1979  set_add_element(stats, stats, s);
1980  return stats;
1981 }
1982 
1983 #define starts_with(s1, s2) (strncmp(s1, s2, strlen(s2))==0) /* a la java */
1984 
1985 /* hmmm... this is poor, should rather rely on use-def chains.
1986  */
1987 static bool any_use_statement(set stats)
1988 {
1989  bool used = false;
1990  SET_FOREACH(statement, s, stats)
1991  {
1993  if (c) {
1994  const char* name = entity_local_name(call_function(c));
1995  pips_debug(9, "call to %s\n", name);
1996  // some freia utils are considered harmless,
1997  // others imply an actual "use"
1998  if (!same_string_p(name, FREIA_FREE) &&
1999  !same_string_p(name, FREIA_ALLOC) &&
2000  !same_string_p(name, "freia_common_rx_image"))
2001  used = true;
2002  }
2003  }
2004  return used;
2005 }
2006 
2007 /* @return whether there is a significant use of e outside of stats
2008  */
2010 (entity e, const hash_table occs, const set stats)
2011 {
2012  if (!occs) return true; // safe
2013  set all_stats = (set) hash_get(occs, e);
2014  pips_assert("some statement set", all_stats);
2015  set others = set_make(set_pointer);
2016  set_difference(others, all_stats, stats);
2017  // is there something significant in others?
2018  bool used = any_use_statement(others);
2019  set_free(others);
2020  pips_debug(9, "%s is %susefull\n", entity_name(e), used? "": "not ");
2021  return used;
2022 }
2023 
2024 /* hmmm...
2025  */
2027 {
2028  bool used = false;
2029  FOREACH(dag, d, ld)
2030  {
2031  FOREACH(dagvtx, v, dag_inputs(d))
2032  {
2033  if (dagvtx_image(v)==img)
2034  {
2035  used = true;
2036  break;
2037  }
2038  }
2039  if (used) break;
2040  }
2041  pips_debug(8, "%s: %s\n", entity_name(img), bool_to_string(used));
2042  return used;
2043 }
2044 
2045 static bool dag_image_is_an_input(dag d, entity img)
2046 {
2047  bool is_input = false;
2048  FOREACH(dagvtx, v, dag_inputs(d))
2049  {
2050  if (dagvtx_image(v)==img)
2051  {
2052  is_input = true;
2053  break;
2054  }
2055  }
2056 
2057  pips_debug(4, "image %s input: %s\n",
2058  entity_name(img), bool_to_string(is_input));
2059 
2060  return is_input;
2061 }
2062 
2063 /* (re)compute the list of *GLOBAL* input & output images for this dag
2064  * ??? BUG the output is rather an approximation
2065  * should rely on used defs or out effects for the underlying
2066  * sequence. however, the status of chains and effects on C does not
2067  * allow it at the time. again after a look at DG (FC 08/08/2011)
2068  * @param d dag to consider
2069  * @param occs statement image occurences, may be NULL
2070  * @param output_images images that are output, may be NULL
2071  * @param ld list of some other dags, possibly NIL
2072  */
2074  dag d,
2075  const hash_table occs, const set output_images, const list ld, bool inloop)
2076 {
2077  pips_debug(4, "inloop=%s\n", bool_to_string(inloop));
2078 
2079  set outvars = set_make(set_pointer);
2080  set outs = set_make(set_pointer);
2081  set toremove = set_make(set_pointer);
2082  set stats = dag_stats(d);
2083 
2084  FOREACH(dagvtx, v, dag_vertices(d))
2085  {
2086  pips_debug(8, "considering vertex %" _intFMT "\n", dagvtx_number(v));
2087  vtxcontent c = dagvtx_content(v);
2088  // skip special input nodes...
2089  if (dagvtx_number(v)!=0)
2090  {
2091  // get entity produced by vertex
2092  entity out = vtxcontent_out(c);
2093 
2094  pips_debug(8, "entity is %s\n", safe_entity_name(out));
2095 
2096  if (// we have an image
2097  out!=entity_undefined &&
2098  // it is not already an output
2099  !set_belong_p(outvars, out) &&
2100  // and either...
2101  (// this image is used as output (typically a tx call)
2102  (output_images && set_belong_p(output_images, out)) ||
2103  // no successors to this vertex BUT it is used somewhere (else?)
2104  (!dagvtx_succs(v) && other_significant_uses(out, occs, stats)) ||
2105  // all non-empty successors are measures?!
2106  (dagvtx_succs(v) && all_mesures_p(dagvtx_succs(v))) ||
2107  // new function parameter not yet an output
2108  (formal_parameter_p(out) && !set_belong_p(outvars, out)) ||
2109  // hmmm... yet another hack for freia_61
2111  // an output image is only reused by this dag within a loop?
2112  (inloop && dag_image_is_an_input(d, out))))
2113  {
2114  pips_debug(7, "appending %" _intFMT "\n", dagvtx_number(v));
2115  set_add_element(outvars, outvars, out);
2116  set_add_element(outs, outs, v);
2117  }
2118  }
2119  else
2120  {
2121  // ??? this aborts with terapix...
2122  // pips_assert("is an input vertex", gen_in_list_p(v, dag_inputs(d)));
2123  if (!dagvtx_succs(v))
2124  set_add_element(toremove, toremove, v);
2125  }
2126  }
2127 
2128  ifdebug(8)
2129  {
2130  dag_dump(stderr, "dag_compute_outputs", d);
2131  set_fprint(stderr, "new outs", outs, (gen_string_func_t) dagvtx_number_str);
2132  }
2133 
2134  // cleanup unused node inputs
2135  SET_FOREACH(dagvtx, vr, toremove)
2136  dag_remove_vertex(d, vr);
2137 
2140 
2141  // cleanup
2142  set_free(stats);
2143  set_free(outs);
2144  set_free(outvars);
2145  set_free(toremove);
2146 }
2147 
2149 {
2150  // pips_debug(9, "target is %"_intFMT"\n", dagvtx_number(target));
2151  FOREACH(dagvtx, v, dag_vertices(d))
2152  if (dagvtx_number(target)==dagvtx_number(v))
2153  return v;
2154  pips_internal_error("twin vertex not found for %" _intFMT "\n",
2155  dagvtx_number(target));
2156  return NULL;
2157 }
2158 
2159 /* catch some cases of missing outs between splits...
2160  * for "freia_scalar_03"...
2161  * I'm not that sure about the algorithm.
2162  * This should rely be based on the CHAINS/DG, but the status still seems
2163  * hopeless, as too many arcs currently kept (FC 08/08/2011)
2164  * @param dfull full dag
2165  */
2167 {
2168  // cleanup inputs?
2169  // cleanup outputs
2170  FOREACH(dagvtx, v, dag_vertices(d))
2171  {
2172  // skip input nodes
2173  if (dagvtx_number(v)==0)
2174  continue;
2175 
2176  dagvtx twin = find_twin_vertex(dfull, v);
2177  if (// the vertex was an output node in the full dag
2178  gen_in_list_p(twin, dag_outputs(dfull)) ||
2179  // OR there were more successors in the full dag
2181  {
2182  pips_debug(4, "adding %" _intFMT " as output\n", dagvtx_number(v));
2183  dag_outputs(d) = gen_once(v, dag_outputs(d));
2184  }
2185  }
2186 }
2187 
2188 /* remove unneeded statements?
2189  * you must know they are really un-needed!
2190  */
2192 {
2193  set toremove = set_make(set_pointer);
2194 
2195  FOREACH(dagvtx, v, dag_vertices(d))
2196  if (dagvtx_other_stuff_p(v))
2197  set_add_element(toremove, toremove, v);
2198 
2199  SET_FOREACH(dagvtx, vr, toremove)
2200  dag_remove_vertex(d, vr);
2201 }
2202 
2203 /* ??? I'm unsure about what happens to dead code in the pipeline...
2204  */
2205 
2206 /* ??? BUG the code may not work properly when image variable are
2207  * reused within a pipe. The underlying issues are subtle and
2208  * would need careful thinking: the initial code is correct, the dag
2209  * representation is correct, but the generated code may reorder
2210  * dag vertices so that reused variables are made to interact one with
2211  * the other. Maybe I should recreate output variables in the generated code
2212  * for every pipeline. this would imply a cleanup phase to removed
2213  * unused images at the end. I would really need an SSA form on
2214  * images? this function checks the assumption before proceeding
2215  * further.
2216  */
2218 {
2219  set outs = set_make(set_pointer);
2220  FOREACH(dagvtx, v, dag_vertices(d))
2221  {
2222  vtxcontent c = dagvtx_content(v);
2223  entity out = vtxcontent_out(c);
2224  if (out!=entity_undefined)
2225  {
2226  if (set_belong_p(outs, out)) {
2227  set_free(outs);
2228  return false;
2229  }
2230  set_add_element(outs, outs, out);
2231  }
2232  }
2233  set_free(outs);
2234  return true;
2235 }
2236 
2237 /* returns whether there is a scalar RW dependency from any vs to v
2238  */
2239 static bool any_scalar_dep(dagvtx v, set vs)
2240 {
2241  bool dep = false;
2242  statement target = dagvtx_statement(v);
2243 
2244  // hmmm... may be called on a input node
2245  if (!target) return dep;
2246 
2247  SET_FOREACH(dagvtx, source, vs)
2248  {
2249  if (source==v)
2250  continue;
2251 
2252  pips_debug(9, "%"_intFMT" rw dep to %"_intFMT"?\n",
2253  dagvtx_number(source), statement_number(target));
2254  if (freia_scalar_rw_dep(dagvtx_statement(source), target, NULL))
2255  {
2256  dep = true;
2257  break;
2258  }
2259  }
2260 
2261  ifdebug(8) {
2262  string svs = set_to_string("vs", vs, (gen_string_func_t) dagvtx_number_str);
2263  pips_debug(8, "scalar rw dep on %d for (%s): %s\n",
2264  (int) dagvtx_number(v), svs, bool_to_string(dep));
2265  free(svs);
2266  }
2267 
2268  return dep;
2269 }
2270 
2271 /* check scalar dependency from computed to v.
2272  */
2273 static bool
2275 {
2276  bool okay = true;
2277 
2278  // scan in statement order... does it matter?
2280  FOREACH(dagvtx, pv, lv)
2281  {
2282  // all previous have been scanned
2283  if (pv==v) break;
2285  !set_belong_p(computed, pv))
2286  {
2287  okay = false;
2288  break;
2289  }
2290  }
2291  gen_free_list(lv);
2292 
2293  pips_debug(8, "all %d deps are okay: %s\n",
2294  (int) dagvtx_number(v), bool_to_string(okay));
2295  return okay;
2296 }
2297 
2298 /* return the vertices which may be computed from the list of
2299  * available images, excluding vertices in exclude.
2300  * return a list for determinism.
2301  * @param d is the considered full dag
2302  * @param computed holds all previously computed vertices
2303  * @param currents holds those in the current pipeline
2304  * @params maybe holds vertices with live images
2305  */
2307  (dag d, const set computed, const set maybe, const set currents)
2308 {
2309  list computable = NIL;
2310  set local_currents = set_make(set_pointer);
2311  set not_computed = set_make(set_pointer);
2312  set not_computed_before = set_make(set_pointer);
2313 
2314  set_assign(local_currents, currents);
2315 
2316  FOREACH(dagvtx, v, dag_vertices(d))
2317  if (!set_belong_p(computed, v))
2318  set_add_element(not_computed, not_computed, v);
2319 
2320  // hmmm... should reverse the list to handle implicit dependencies?
2321  // where, there is an assert() to check that it does not happen.
2323 
2324  FOREACH(dagvtx, v, lv)
2325  {
2326  if (set_belong_p(computed, v))
2327  continue;
2328 
2329  if (dagvtx_other_stuff_p(v))
2330  {
2331  // a vertex with other stuff is assimilated to the pipeline
2332  // as soon as its dependences are fullfilled.
2333  // I have a problem here... I really need use_defs?
2334  if (all_previous_stats_with_deps_are_computed(d, computed, v))
2335  {
2336  computable = CONS(dagvtx, v, computable);
2337  set_add_element(local_currents, local_currents, v);
2338  set_del_element(not_computed, not_computed, v);
2339  }
2340  }
2341  else // we have an image computation
2342  {
2343  list preds = dag_vertex_preds(d, v);
2344  pips_debug(8, "%d predecessors to %" _intFMT "\n",
2345  (int) gen_length(preds), dagvtx_number(v));
2346 
2347  // build subset of "not computed" which should occur before v
2348  // from the initial sequence point of view
2349  set_clear(not_computed_before);
2350  SET_FOREACH(dagvtx, vnc, not_computed)
2351  {
2352  if (dagvtx_number(vnc)<dagvtx_number(v))
2353  set_add_element(not_computed_before, not_computed_before, vnc);
2354  }
2355 
2356  if(// no scalar dependencies in the current pipeline
2357  !any_scalar_dep(v, local_currents) &&
2358  // or in the future of the graph
2359  !any_scalar_dep(v, not_computed_before) &&
2360  // and image dependencies are fulfilled.
2361  list_in_set_p(preds, maybe))
2362  {
2363  computable = CONS(dagvtx, v, computable);
2364  // we do not want deps with other currents considered!
2365  set_add_element(local_currents, local_currents, v);
2366  set_del_element(not_computed, not_computed, v);
2367  }
2368 
2369  gen_free_list(preds), preds = NIL;
2370  }
2371 
2372  // update availables: not needed under assert for no img reuse.
2373  // if (vtxcontent_out(c)!=entity_undefined)
2374  // set_del_element(avails, avails, vtxcontent_out(c));
2375  }
2376 
2377  // cleanup
2378  set_free(local_currents);
2379  set_free(not_computed);
2380  set_free(not_computed_before);
2381  gen_free_list(lv);
2382  return computable;
2383 }
2384 
2386 {
2387  FOREACH(dagvtx, v, lv)
2388  {
2390  if (pstatement_statement_p(ps))
2392  }
2393 }
2394 
2395 /* convert the first n items in list args to entities.
2396  */
2397 static list
2398 fs_expression_list_to_entity_list(list /* of expression */ args, int nargs)
2399 {
2400  list /* of entity */ lent = NIL;
2401  int n=0;
2402  FOREACH(expression, ex, args)
2403  {
2404  syntax s = expression_syntax(ex);
2405  pips_assert("is a ref", syntax_reference_p(s));
2406  reference r = syntax_reference(s);
2407  pips_assert("simple ref", reference_indices(r)==NIL);
2408  lent = CONS(entity, reference_variable(r), lent);
2409  if (++n==nargs) break;
2410  }
2411  lent = gen_nreverse(lent);
2412  return lent;
2413 }
2414 
2415 /* extract first entity item from list.
2416  */
2418 {
2419  list l = gen_list_head(lp, 1);
2420  entity e = ENTITY(CAR(l));
2421  gen_free_list(l);
2422  return e;
2423 }
2424 
2425 /* append statement s to dag d
2426  */
2428 {
2429  pips_debug(5, "adding statement %" _intFMT "\n", statement_number(s));
2430 
2432 
2433  if (c && entity_freia_api_p(call_function(c)))
2434  {
2435  entity called = call_function(c);
2436  const freia_api_t * api = hwac_freia_api(entity_local_name(called));
2437  pips_assert("some api", api!=NULL);
2438  list /* of entity */ args =
2440  api->arg_img_in+api->arg_img_out);
2441 
2442  // extract arguments
2444  pips_assert("one out image max for an AIPO", api->arg_img_out<=1);
2445  if (api->arg_img_out==1)
2446  out = extract_fist_item(&args);
2447  list ins = gen_list_head(&args, api->arg_img_in);
2448  pips_assert("no more arguments", gen_length(args)==0);
2449 
2450  vtxcontent cont =
2453  (api, &vtxcontent_optype(cont), &vtxcontent_opid(cont));
2454 
2455  dagvtx nv = make_dagvtx(cont, NIL);
2456  dag_append_vertex(d, nv);
2457  }
2458  else // some other kind of statement that we may keep in the DAG
2459  {
2460  dagvtx nv =
2463  dag_vertices(d) = CONS(dagvtx, nv, dag_vertices(d));
2464  }
2465 }
2466 
2467 /* build a full dag from list of statements ls.
2468  * @param module
2469  * @param list of statements in sequence
2470  * @param number dag identifier in function
2471  * @param occurrences entity -> set of statements where they appear
2472  * @param output_images set of images that are output
2473  * @param ld list of other dags... (???)
2474  * @param inloop whether we might be in a loop
2475  */
2477  string module, list ls, int number,
2478  const hash_table occurrences, const set output_images, const list ld,
2479  bool inloop)
2480 {
2481  // build full dag
2482  dag fulld = make_dag(NIL, NIL, NIL);
2483 
2484  FOREACH(statement, s, ls)
2485  dag_append_freia_call(fulld, s);
2486 
2487  dag_compute_outputs(fulld, occurrences, output_images, ld, inloop);
2488 
2489  ifdebug(3) dag_dump(stderr, "fulld", fulld);
2490 
2491  // dump resulting dag
2492  dag_dot_dump_prefix(module, "dag_", number, fulld, NIL, NIL);
2493 
2494  return fulld;
2495 }
2496 
2497 /* tell whether we have something to do with images
2498  ??? hmmm... what about vol(cst_img()) ?
2499  */
2501 {
2502  return !dag_inputs(d) && !dag_outputs(d);
2503 }
2504 
2505 /**************************************************** NEW INTERMEDIATE IMAGE */
2506 
2507 // in phrase
2508 extern entity clone_variable_with_new_name(entity, const char*, const char*);
2509 // in pipsmake
2510 extern string compilation_unit_of_module(const char *);
2511 
2512 // ??? could not find this anywhere
2513 static entity freia_data2d_field(string field)
2514 {
2515  string cu =
2518  pips_assert("freia_data2d type found", fi!=entity_undefined);
2519  type ut = ultimate_type(entity_type(fi));
2520 
2521  list fields =
2523  pips_assert("some fields", fields);
2524  FOREACH(entity, f, fields)
2525  if (same_string_p(field,
2527  return f;
2528  // should not get there
2529  pips_internal_error("cannot find freia_data2d field %s\n", field);
2530  return NULL;
2531 }
2532 
2533 static expression do_point_to(entity var, string field_name)
2534 {
2535  // entity f2d = local_name_to_top_level_entity(FREIA_IMAGE_TYPE);
2536  expression evar = entity_to_expression(var);
2541  NULL)));
2542 }
2543 
2544 /************************************* FIND FIRST REFERENCED IMAGE SOMEWHERE */
2545 // hmmm... only works if initialized at the declaration level
2546 
2548 {
2549  entity var = reference_variable(r);
2550  if (freia_image_variable_p(var))
2551  {
2552  *image = var;
2553  gen_recurse_stop(NULL);
2554  }
2555  // do not go in array indexes
2556  return false;
2557 }
2558 
2559 // ??? l'arrache (tm)
2560 static entity get_upper_model(entity model, const hash_table occs)
2561 {
2562  entity image = NULL;
2563  // first look in declarations
2566  // then look for statements...
2567  if (!image && hash_defined_p(occs, model))
2568  {
2569  SET_FOREACH(statement, s, (set) hash_get(occs, model))
2570  {
2571  if (is_freia_alloc(s))
2574  if (image && image!=model) break;
2575  image = NULL;
2576  }
2577  }
2578  // go upwards!
2579  if (image && image!=model) image = get_upper_model(image, occs);
2580  return image? image: model;
2581 }
2582 
2583 /* @return statement where image is allocated/deallocated
2584  * maybe I should build another hash_table for this purpose?
2585  */
2587 (entity image, const hash_table occs, bool alloc)
2588 {
2589  pips_debug(8, "look for %s statement for %s\n",
2590  alloc? "allocation": "deallocation", entity_name(image));
2591 
2592  if (hash_defined_p(occs, image))
2593  {
2594  SET_FOREACH(statement, s, (set) hash_get(occs, image))
2595  {
2596  // it may already have been switched to a sequence by a prior insert...
2597  // ??? it is unclear why I encounter nested sequences
2598  while (statement_sequence_p(s))
2600 
2601  // fprintf(stderr, "statement %"_intFMT"?\n", statement_number(s));
2602  if (alloc && is_freia_alloc(s))
2603  {
2604  call c = statement_call(s);
2605  pips_assert("must be an assignment", ENTITY_ASSIGN_P(call_function(c)));
2606  entity var;
2609  if (var==image) return s;
2610  }
2611  else if (!alloc && is_freia_dealloc(s))
2612  {
2613  call c = statement_call(s);
2614  entity var;
2617  if (var==image) return s;
2618  }
2619  }
2620  }
2621  return NULL;
2622 }
2623 
2624 /* @return a new image from the model
2625  */
2627 {
2628  entity img = NULL;
2629  int index = 1;
2630  do
2631  {
2632  string varname;
2633  int n = asprintf(&varname, "%s_%d", entity_local_name(model), index);
2634  pips_assert("asprintf succeeded", n!=-1);
2636  (model, varname, module_local_name(get_current_module_entity()));
2637  free(varname);
2638  index++;
2639  if (img)
2640  {
2641  // use the reference of the model instead of the model itself, if found.
2642  entity ref = get_upper_model(model, occs);
2643 
2646  do_point_to(ref, "bpp"),
2647  do_point_to(ref, "widthWa"),
2648  do_point_to(ref, "heightWa"),
2649  NULL));
2650 
2651  // handle allocation as the declaration initial value, if possible
2652  if (formal_parameter_p(ref))
2653  {
2654  free_value(entity_initial(img));
2656  }
2657  else
2658  {
2660 
2661  if (sa)
2662  {
2663  // insert statement just after the reference declaration
2664  free_value(entity_initial(img));
2666 
2669  insert_statement(sa, na, false);
2670  }
2671  else
2672  {
2673  // this may happen if the "ref" is allocated at its declaration point,
2674  // as this statement is not currently found by our search
2675 
2676  // ??? try with a direct declaration
2677  free_value(entity_initial(img));
2678  entity_initial(img) =
2680  }
2681  }
2682 
2683  // should not be a parameter! overwrite storage if so...
2684  if (formal_parameter_p(img))
2685  {
2688  // make_storage_ram(make_ram(get_current_module_entity(),
2689  // entity_undefined, UNKNOWN_RAM_OFFSET, NIL));
2690  }
2691  }
2692  }
2693  while (img==NULL);
2694  return img;
2695 }
2696 
2697 /************************************************** FREIA IMAGE SUBSTITUTION */
2698 
2699 typedef struct { entity old, new; bool write; } swis_ctx;
2700 
2701 static void swis_ref_rwt(reference r, swis_ctx * ctx)
2702 {
2703  if (reference_variable(r)==ctx->old)
2704  reference_variable(r) = ctx->new;
2705 }
2706 
2707 static bool swis_call_flt(call c, swis_ctx * ctx)
2708 {
2710  if (api)
2711  {
2712  list args = call_arguments(c);
2713  pips_assert("freia api call length is ok",
2714  gen_length(args)== (api->arg_img_out + api->arg_img_in +
2715  api->arg_misc_out + api->arg_misc_in));
2716  unsigned int i;
2717  // output arguments
2718  for(i=0; i<api->arg_img_out; i++)
2719  {
2720  if (!ctx->write)
2722  args = CDR(args);
2723  }
2724  // input arguments
2725  for(i=0; i<api->arg_img_in; i++)
2726  {
2727  if (ctx->write)
2729  args = CDR(args);
2730  }
2731  // skip remainder anyway
2732  while (args)
2733  {
2735  args = CDR(args);
2736  }
2737  }
2738  // else this is not an AIPO call... we substitute everywhere
2739  return true;
2740 }
2741 
2742 /* switch read or written image in statement
2743  * if this is an AIPO call, only substitute output or input depending on write
2744  * otherwise all occurrences are substituted
2745  */
2747  statement s, entity old, entity img, bool write)
2748 {
2749  swis_ctx ctx = { old, img, write };
2750  gen_context_multi_recurse(s, &ctx,
2753  NULL);
2754 }
2755 
2756 /* switch to new image variable in v & its direct successors
2757  */
2758 static void switch_image_variable(dagvtx v, entity old, entity img)
2759 {
2760  vtxcontent c = dagvtx_content(v);
2761  pips_assert("switch image output", vtxcontent_out(c)==old);
2762  vtxcontent_out(c) = img;
2763  statement st = dagvtx_statement(v);
2764  pips_assert("some production statement", st!=NULL);
2765  freia_switch_image_in_statement(st, old, img, true);
2766  FOREACH(dagvtx, s, dagvtx_succs(v))
2767  {
2768  vtxcontent cs = dagvtx_content(s);
2769  gen_replace_in_list(vtxcontent_inputs(cs), old, img);
2770  statement st = dagvtx_statement(s);
2771  pips_assert("some producer statement", st!=NULL);
2772  freia_switch_image_in_statement(st, old, img, false);
2773  }
2774 }
2775 
2776 /* fix intermediate image reuse in dag
2777  * @return new image entities to be added to declarations
2778  */
2780 {
2781  list images = NIL;
2783 
2784  // dag vertices are assumed to be in reverse statement order,
2785  // so that last write is seen first and is kept by default
2786  FOREACH(dagvtx, v, dag_vertices(d))
2787  {
2788  entity img = dagvtx_image(v);
2789  if (!img || img==entity_undefined)
2790  continue;
2791 
2792  if (set_belong_p(seen, img) &&
2793  // but take care of image reuse, we must keep input images!
2794  !gen_in_list_p(v, dag_inputs(d)))
2795  {
2796  entity new_img = new_local_image_variable(img, occs);
2797  switch_image_variable(v, img, new_img);
2798  images = CONS(entity, new_img, images);
2799  // keep track of new->old image mapping, to reverse it latter eventually
2800  hash_put(init, new_img, img);
2801  }
2802  set_add_element(seen, seen, img);
2803  }
2804 
2805  set_free(seen);
2806  return images;
2807 }
2808 
2809 /************************************************************* DAG SPLITTING */
2810 
2811 /* @brief split a dag on scalar dependencies only, with a greedy heuristics.
2812  * @param initial dag to split
2813  * @param alone_only whether to keep it alone (for non implemented cases)
2814  * @param choose_vertex chose a vertex from computable ones, may be NULL
2815  * @param priority how to prioritize computable vertices
2816  * @param priority_update stuff to help prioritization
2817  * @return a list of sub-dags, some of which may contain no image operations
2818  * For terapix, this pass also decides the schedule of image operations,
2819  * with the aim or reducing the number of necessary imagelets, so as to
2820  * maximise imagelet size.
2821  */
2822 list // of dags
2824  bool (*alone_only)(const dagvtx),
2825  dagvtx (*choose_vertex)(const list, bool),
2826  gen_cmp_func_t priority,
2827  void (*priority_update)(const dag),
2828  const set output_images)
2829 {
2830  if (!single_image_assignement_p(initial))
2831  // well, it should work most of the time, so only a warning
2832  pips_user_warning("still some image reuse...\n");
2833 
2834  // ifdebug(1) pips_assert("initial dag ok", dag_consistent_p(initial));
2835  // if everything was removed by optimizations, there is nothing to do.
2836  if (dag_computation_count(initial)==0) return NIL;
2837 
2838  // work on a copy of the dag.
2839  dag dall = copy_dag(initial);
2840  list ld = NIL;
2841  set
2842  // current set of vertices to group
2844  // all vertices which are considered computed
2845  computed = set_make(set_pointer);
2846 
2847  do
2848  {
2849  list lcurrent = NIL, computables;
2850  set_clear(current);
2851  set_clear(computed);
2852  set_assign_list(computed, dag_inputs(dall));
2853 
2854  // GLOBAL for sorting
2855  if (priority_update) priority_update(dall);
2856 
2857  // transitive closure
2858  while ((computables =
2859  dag_computable_vertices(dall, computed, computed, current)))
2860  {
2861  ifdebug(7) {
2862  FOREACH(dagvtx, v, computables)
2863  dagvtx_dump(stderr, "computable", v);
2864  }
2865 
2866  // sort, mostly for determinism
2867  gen_sort_list(computables, priority);
2868 
2869  // choose one while building the schedule?
2870  dagvtx choice = choose_vertex?
2871  choose_vertex(computables, lcurrent? true: false):
2872  DAGVTX(CAR(computables));
2873  gen_free_list(computables), computables = NIL;
2874 
2875  ifdebug(7)
2876  dagvtx_dump(stderr, "choice", choice);
2877 
2878  // do not add if not alone
2879  if (alone_only && alone_only(choice) && lcurrent)
2880  break;
2881 
2883  set_add_element(computed, computed, choice);
2884  lcurrent = gen_nconc(lcurrent, CONS(dagvtx, choice, NIL));
2885 
2886  // getout if was alone
2887  if (alone_only && alone_only(choice))
2888  break;
2889  }
2890 
2891  // is there something?
2892  if (lcurrent)
2893  {
2894  // build extracted dag
2895  dag nd = make_dag(NIL, NIL, NIL);
2896  FOREACH(dagvtx, v, lcurrent)
2897  {
2898  pips_debug(7, "extracting node %" _intFMT "\n", dagvtx_number(v));
2900  }
2901  dag_compute_outputs(nd, NULL, output_images, NIL, false);
2903 
2904  ifdebug(7) {
2905  // dag_dump(stderr, "updated dall", dall);
2906  dag_dump(stderr, "pushed dag", nd);
2907  }
2908 
2909  // ??? hmmm... should not be needed?
2910  freia_hack_fix_global_ins_outs(initial, nd);
2911 
2912  // update global list of dags to return.
2913  ld = CONS(dag, nd, ld);
2914 
2915  // cleanup full dag for next round
2916  FOREACH(dagvtx, w, lcurrent)
2917  dag_remove_vertex(dall, w);
2918 
2919  gen_free_list(lcurrent), lcurrent = NIL;
2920  }
2921  }
2922  while (set_size(current));
2923 
2924  free_dag(dall);
2925  return gen_nreverse(ld);
2926 }
2927 
2928 /*********************************************** BUILD A CONNECTED COMPOTENT */
2929 
2930 // debug
2931 static string dagvtx_nb(const void * s) {
2932  return i2a((int) dagvtx_number((dagvtx) s));
2933 }
2934 
2935 /* extract a sublist of lv which is a connected component.
2936  * update lv so that the extracted vertices are not there.
2937  * the extracted list must keep the order of the initial list!
2938  */
2940  dag d, list *plv, bool (*compat)(const dagvtx, const set, const dag))
2941 {
2942  ifdebug(7) {
2943  pips_debug(7, "entering\n");
2944  gen_fprint(stderr, "initial list", *plv, dagvtx_nb);
2945  }
2946 
2947  set connected = set_make(set_pointer);
2948  set extracted = set_make(set_pointer);
2949 
2950  // boostrap.
2951  dagvtx first = DAGVTX(CAR(*plv));
2952  set_add_element(extracted, extracted, first);
2953  set_add_element(connected, connected, first);
2954  set_append_list(connected, dagvtx_succs(first));
2955 
2956  bool stable = false;
2957  while (!stable)
2958  {
2959  stable = true;
2960 
2961  // expand thru common dag inputs
2962  FOREACH(dagvtx, i, dag_inputs(d))
2963  {
2964  bool merge = false;
2965  FOREACH(dagvtx, v, dagvtx_succs(i)) {
2966  if (set_belong_p(extracted, v)) {
2967  merge = true;
2968  break;
2969  }
2970  }
2971  if (merge)
2972  set_append_list(connected, dagvtx_succs(i));
2973  }
2974 
2975  // expand with new vertices from the list
2976  FOREACH(dagvtx, v, *plv)
2977  {
2978  if (!set_belong_p(extracted, v) && (!compat || compat(v, extracted, d)))
2979  {
2980  // do we need to extract v?
2981  bool connect = set_belong_p(connected, v);
2982  if (!connect) {
2983  FOREACH(dagvtx, s, dagvtx_succs(v))
2984  if (set_belong_p(extracted, s)) {
2985  connect = true;
2986  break;
2987  }
2988  }
2989  if (connect) {
2990  stable = false;
2991  set_add_element(extracted, extracted, v);
2992  set_add_element(connected, connected, v);
2993  set_append_list(connected, dagvtx_succs(v));
2994  }
2995  }
2996  }
2997  }
2998 
2999  // split initial list
3000  list lnew = NIL, lold = NIL;
3001  FOREACH(dagvtx, v, *plv)
3002  {
3003  if (set_belong_p(extracted, v))
3004  lnew = CONS(dagvtx, v, lnew);
3005  else
3006  lold = CONS(dagvtx, v, lold);
3007  }
3008  lnew = gen_nreverse(lnew);
3009  gen_free_list(*plv);
3010  *plv = gen_nreverse(lold);
3011 
3012  set_free(connected);
3013  set_free(extracted);
3014 
3015  ifdebug(7) {
3016  pips_debug(7, "exiting\n");
3017  gen_fprint(stderr, "final list", *plv, dagvtx_nb);
3018  gen_fprint(stderr, "returned", lnew, dagvtx_nb);
3019  }
3020 
3021  return lnew;
3022 }
3023 
3025 {
3026  list nl = NIL;
3027  FOREACH(dagvtx, v, lv)
3028  if (dagvtx_number(v)!=0)
3029  nl = CONS(dagvtx, v, nl);
3030  return gen_nreverse(nl);
3031 }
3032 
3033 /* build connected components
3034  */
3036 {
3037  list lnd = NIL;
3038  list vertices = copy_vertices(dag_vertices(d));
3039 
3040  pips_debug(3, "considering %"_intFMT" vertices\n", gen_length(vertices));
3041  ifdebug(3)
3042  gen_fprint(stderr, "vertices", vertices, dagvtx_nb);
3043 
3044  while (vertices)
3045  {
3046  list cv = dag_connected_component(d, &vertices, NULL);
3047  pips_assert("some connected vertices", cv);
3048  if (!vertices) { // take remaining dag in full
3049  lnd = CONS(dag, d, lnd);
3050  break;
3051  }
3052 
3053  ifdebug(3) gen_fprint(stderr, "connected component", cv, dagvtx_nb);
3054 
3055  // else there seems to be an actual split...
3056  dag nd = make_dag(NIL, NIL, NIL);
3057  cv = gen_nreverse(cv); // ??? they must be introduced in reverse order?
3058  FOREACH(dagvtx, v, cv)
3060  dag_compute_outputs(nd, NULL, output_images, NIL, false);
3062  // ???
3064  lnd = CONS(dag, nd, lnd);
3065 
3066  // cleanup other dag for next round
3067  FOREACH(dagvtx, v, cv)
3068  dag_remove_vertex(d, v);
3069  dag_compute_outputs(d, NULL, output_images, NIL, false);
3071  }
3072 
3073  pips_debug(3, "found %"_intFMT" connected components\n", gen_length(lnd));
3074  return gen_nreverse(lnd);
3075 }
static hash_table seen
static function to store whether a module has been seen during the recursive generation of the daVinc...
Definition: graph.c:85
void free_dag(dag p)
pstatement make_pstatement_empty(void)
dagvtx make_dagvtx(vtxcontent a1, list a2)
dagvtx copy_dagvtx(dagvtx p)
DAGVTX.
vtxcontent make_vtxcontent(intptr_t a1, intptr_t a2, pstatement a3, list a4, entity a5)
dag make_dag(list a1, list a2, list a3)
pstatement make_pstatement_statement(statement _field_)
dag copy_dag(dag p)
DAG.
void free_dagvtx(dagvtx p)
call make_call(entity a1, list a2)
Definition: ri.c:269
value make_value_expression(expression _field_)
Definition: ri.c:2850
storage make_storage_rom(void)
Definition: ri.c:2285
expression copy_expression(expression p)
EXPRESSION.
Definition: ri.c:850
void free_expression(expression p)
Definition: ri.c:853
void free_storage(storage p)
Definition: ri.c:2231
void free_value(value p)
Definition: ri.c:2787
static int count
Definition: SDG.c:519
static reference ref
Current stmt (an integer)
Definition: adg_read_paf.c:163
#define append(s)
text text_region_no_action(effect reg) input : a region output : a text consisting of several lines o...
Definition: prettyprint.c:77
static FILE * out
Definition: alias_check.c:128
void const char const char const int
char * alloc(int size)
ALLOC is an "iron-clad" version of malloc(3).
Definition: build.c:501
void dag_cleanup_other_statements(dag d)
remove unneeded statements? you must know they are really un-needed!
Definition: dag-utils.c:2191
void dag_consistency_asserts(dag d)
do some consistency checking...
Definition: dag-utils.c:531
static bool switch_vertex_to_assign(dagvtx target, dagvtx source)
replace target measure to a copy of source result...
Definition: dag-utils.c:725
static entity get_upper_model(entity model, const hash_table occs)
Definition: dag-utils.c:2560
static void switch_vertex_to_a_copy(dagvtx target, dagvtx source, list tpreds)
replace target vertex by a copy of source results...
Definition: dag-utils.c:823
static bool variable_used_as_later_input(entity img, list ld)
hmmm...
Definition: dag-utils.c:2026
list dag_split_connected_components(dag d, set output_images)
build connected components
Definition: dag-utils.c:3035
static void set_aipo_call(dagvtx v, string name, entity img, expression val)
switch vertex statement to an aipo call
Definition: dag-utils.c:974
static list copy_vertices(list lv)
Definition: dag-utils.c:3024
_int dagvtx_optype(const dagvtx v)
Definition: dag-utils.c:116
#define SCL_DEP
Definition: dag-utils.c:231
list dag_vertex_preds(const dag d, const dagvtx target)
return target predecessor vertices as a list.
Definition: dag-utils.c:680
_int dagvtx_number(const dagvtx v)
returns the vertex number, i.e.
Definition: dag-utils.c:98
static bool any_scalar_dep(dagvtx v, set vs)
returns whether there is a scalar RW dependency from any vs to v
Definition: dag-utils.c:2239
int dag_computation_count(const dag d)
return the number of actual operations in dag d.
Definition: dag-utils.c:665
bool dagvtx_other_stuff_p(const dagvtx v)
a vertex with a non AIPO or image related statement.
Definition: dag-utils.c:76
void dagvtx_nb_dump(FILE *out, const string what, const list l)
Definition: dag-utils.c:176
static dagvtx find_twin_vertex(dag d, dagvtx target)
Definition: dag-utils.c:2148
bool dag_no_image_operation(dag d)
tell whether we have something to do with images ??? hmmm...
Definition: dag-utils.c:2500
static bool list_commuted_p(const list l1, const list l2)
Definition: dag-utils.c:888
static void check_removed(const dagvtx v, const dagvtx removed)
Definition: dag-utils.c:513
list dag_split_on_scalars(const dag initial, bool(*alone_only)(const dagvtx), dagvtx(*choose_vertex)(const list, bool), gen_cmp_func_t priority, void(*priority_update)(const dag), const set output_images)
split a dag on scalar dependencies only, with a greedy heuristics.
Definition: dag-utils.c:2823
static bool dag_simplify(dag d)
apply basic algebraic simplification to dag
Definition: dag-utils.c:1302
static bool dag_image_is_an_input(dag d, entity img)
Definition: dag-utils.c:2045
static void switch_image_variable(dagvtx v, entity old, entity img)
switch to new image variable in v & its direct successors
Definition: dag-utils.c:2758
int dagvtx_ordering(const dagvtx *v1, const dagvtx *v2)
Definition: dag-utils.c:148
static entity new_local_image_variable(entity model, const hash_table occs)
Definition: dag-utils.c:2626
list dag_fix_image_reuse(dag d, hash_table init, const hash_table occs)
fix intermediate image reuse in dag
Definition: dag-utils.c:2779
static void dag_append_freia_call(dag d, statement s)
append statement s to dag d
Definition: dag-utils.c:2427
static bool dagvtx_is_operator_p(const dagvtx v, const string opname)
Definition: dag-utils.c:390
static bool image_ref_flt(reference r, entity *image)
Definition: dag-utils.c:2547
void dagvtx_dump(FILE *out, const string name, const dagvtx v)
for dag debug.
Definition: dag-utils.c:186
static bool commutative_operation_p(const dagvtx v1, const dagvtx v2)
Definition: dag-utils.c:875
static int dagvtx_cmp_entity(const dagvtx *v1, const dagvtx *v2)
Definition: dag-utils.c:518
static expression compute_constant(string op, expression val1, expression val2)
compute a constant expression for FREIA ??? TODO partial eval if values are constant
Definition: dag-utils.c:957
void freia_hack_fix_global_ins_outs(dag dfull, dag d)
catch some cases of missing outs between splits...
Definition: dag-utils.c:2166
static string dagvtx_nb(const void *s)
Definition: dag-utils.c:2931
static bool any_use_statement(set stats)
hmmm...
Definition: dag-utils.c:1987
static int compatible_reduction_operation(const dagvtx v1, const dagvtx v2)
Definition: dag-utils.c:1395
bool dagvtx_is_measurement_p(const dagvtx v)
returns whether the vertex is an image measurement operation.
Definition: dag-utils.c:623
dagvtx copy_dagvtx_norec(dagvtx v)
copy a vertex, but without its successors.
Definition: dag-utils.c:611
static list fs_expression_list_to_entity_list(list args, int nargs)
convert the first n items in list args to entities.
Definition: dag-utils.c:2398
static void unlink_copy_vertex(dag d, const entity source, dagvtx copy)
"copy" copies "source" image in dag "d".
Definition: dag-utils.c:898
#define aipo_op_p(a, name)
Definition: dag-utils.c:951
static const char * entity_dot_name(entity e)
Definition: dag-utils.c:233
static bool same_operation_p(const dagvtx v1, const dagvtx v2)
Definition: dag-utils.c:866
list dag_computable_vertices(dag d, const set computed, const set maybe, const set currents)
return the vertices which may be computed from the list of available images, excluding vertices in ex...
Definition: dag-utils.c:2307
static bool propagate_constant_image(dagvtx, entity, expression)
recursively propagate a constant image on a vertex
Definition: dag-utils.c:1055
static bool other_significant_uses(entity e, const hash_table occs, const set stats)
Definition: dag-utils.c:2010
static void set_aipo_copy(dagvtx v, entity e)
switch vertex to a copy of an image
Definition: dag-utils.c:1016
dagvtx dagvtx_get_producer(const dag d, const dagvtx sink, const entity e, _int before_number)
return (last) producer of image e for vertex sink, or NULL if none found.
Definition: dag-utils.c:156
string dagvtx_number_str(const dagvtx v)
Definition: dag-utils.c:111
entity dagvtx_image(const dagvtx v)
return the produced image or NULL
Definition: dag-utils.c:82
static void propagate_constant_image_to_succs(dagvtx v, expression val)
propagate constant image to vertex successors
Definition: dag-utils.c:1031
static bool swis_call_flt(call c, swis_ctx *ctx)
Definition: dag-utils.c:2707
entity clone_variable_with_new_name(entity, const char *, const char *)
This function build and return new variable from a variable a_variable, with name new_name.
Definition: phrase_tools.c:269
static bool dag_normalize(dag d)
normalize, that is use less image operators only transformation is: sub_const(i, v) -> add_const(i,...
Definition: dag-utils.c:1351
string compilation_unit_of_module(const char *)
The output is undefined if the module is referenced but not defined in the workspace,...
Definition: module.c:350
static void dagvtx_dot_node(FILE *out, const string prefix, const dagvtx v)
Definition: dag-utils.c:238
void dag_remove_vertex(dag d, const dagvtx v)
remove vertex v from dag d.
Definition: dag-utils.c:570
dag freia_build_dag(string module, list ls, int number, const hash_table occurrences, const set output_images, const list ld, bool inloop)
build a full dag from list of statements ls.
Definition: dag-utils.c:2476
static bool all_mesures_p(list lv)
return whether all vertices in list are mesures...
Definition: dag-utils.c:1957
void dag_dump(FILE *out, const string what, const dag d)
for dag debug
Definition: dag-utils.c:212
statement freia_memory_management_statement(entity image, const hash_table occs, bool alloc)
Definition: dag-utils.c:2587
static void substitute_image_in_statement(dagvtx v, entity source, entity target, bool used)
subtitute produced or used image in the statement of vertex v.
Definition: dag-utils.c:773
#define DOT_SUFFIX
Definition: dag-utils.c:484
static void vertex_list_sorted_by_entities(list l)
Definition: dag-utils.c:524
void freia_dag_optimize(dag d, hash_table exchanges, list *lbefore, list *lafter)
remove dead image operations.
Definition: dag-utils.c:1416
static void dagvtx_dot(FILE *out, const dag d, const dagvtx vtx)
Definition: dag-utils.c:252
static void dagvtx_copy_list_dot(FILE *out, const list ls, const set inputs)
Definition: dag-utils.c:350
list dag_connected_component(dag d, list *plv, bool(*compat)(const dagvtx, const set, const dag))
extract a sublist of lv which is a connected component.
Definition: dag-utils.c:2939
static void dag_remove_unused_inputs(dag d)
remove unused inputs
Definition: dag-utils.c:551
static bool dagvtx_is_copy_p(const dagvtx v)
returns whether the vertex is an image copy operation.
Definition: dag-utils.c:399
static entity extract_fist_item(list *lp)
extract first entity item from list.
Definition: dag-utils.c:2417
void dag_compute_outputs(dag d, const hash_table occs, const set output_images, const list ld, bool inloop)
(re)compute the list of GLOBAL input & output images for this dag ??? BUG the output is rather an app...
Definition: dag-utils.c:2073
static void entity_list_dump(FILE *out, const string what, const list l)
Definition: dag-utils.c:88
static int number_of_copies(list l)
Definition: dag-utils.c:941
static void dagvtx_dot_node_sb(string_buffer sb, const string prefix, const dagvtx v)
Definition: dag-utils.c:245
void dag_dot_dump(const string module, const string name, const dag d, const list lb, const list la)
generate a "dot" format from a dag to a file.
Definition: dag-utils.c:488
void set_append_vertex_statements(set s, list lv)
Definition: dag-utils.c:2385
static void set_aipo_constant(dagvtx, expression)
set vertex as a constant image and propagate to successors
Definition: dag-utils.c:1149
void freia_switch_image_in_statement(statement s, entity old, entity img, bool write)
switch read or written image in statement if this is an AIPO call, only substitute output or input de...
Definition: dag-utils.c:2746
string dagvtx_function_name(const dagvtx v)
Definition: dag-utils.c:126
void dag_dot(FILE *out, const string what, const dag d, const list lb, const list la)
output dag in dot format, for debug or show
Definition: dag-utils.c:409
string dagvtx_operation(const dagvtx v)
Definition: dag-utils.c:134
string dagvtx_compact_operation(const dagvtx v)
Definition: dag-utils.c:140
static entity freia_data2d_field(string field)
Definition: dag-utils.c:2513
static expression constant_image_p(dagvtx)
whether vertex generates a constant image
Definition: dag-utils.c:1159
static bool all_previous_stats_with_deps_are_computed(dag d, const set computed, dagvtx v)
check scalar dependency from computed to v.
Definition: dag-utils.c:2274
static set dag_stats(dag d)
Definition: dag-utils.c:1973
static void swis_ref_rwt(reference r, swis_ctx *ctx)
Definition: dag-utils.c:2701
string dagvtx_to_string(const dagvtx v)
dag-utils.c
Definition: dag-utils.c:49
statement dagvtx_statement(const dagvtx v)
return statement if any, or NULL (for input nodes).
Definition: dag-utils.c:56
static bool all_vertices_are_copies_or_measures_p(const list lv)
Definition: dag-utils.c:931
_int dagvtx_opid(const dagvtx v)
Definition: dag-utils.c:121
void dag_statements(set stats, const dag d)
build the set of actual statements in d
Definition: dag-utils.c:64
static void dagvtx_list_dot(FILE *out, const string comment, const list l, const set used)
Definition: dag-utils.c:376
static entity copy_image_p(dagvtx)
tell whether vertex can be assimilated to a copy e.g.
Definition: dag-utils.c:1235
bool single_image_assignement_p(dag d)
??? I'm unsure about what happens to dead code in the pipeline...
Definition: dag-utils.c:2217
void dag_append_vertex(dag d, dagvtx nv)
append new vertex nv to dag d.
Definition: dag-utils.c:632
static bool gen_list_equals_p(const list l1, const list l2)
Definition: dag-utils.c:707
void dag_dot_dump_prefix(const string module, const string prefix, int number, const dag d, const list lb, const list la)
Definition: dag-utils.c:504
static expression do_point_to(entity var, string field_name)
Definition: dag-utils.c:2533
FILE * safe_fopen(const char *filename, const char *what)
Definition: file.c:67
int safe_fclose(FILE *stream, const char *filename)
Definition: file.c:77
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
bool entity_freia_api_p(const entity f)
returns whether the entity is a freia API (AIPO) function.
Definition: freia-utils.c:806
const freia_api_t * hwac_freia_api(const char *function)
freia-utils.c
Definition: freia-utils.c:455
bool is_freia_dealloc(const statement s)
Definition: freia-utils.c:1007
bool is_freia_alloc(const statement s)
Definition: freia-utils.c:1002
void freia_spoc_set_operation(const freia_api_t *api, _int *type, _int *id)
??? beurk: I keep the operation as two ints for code regeneration.
Definition: freia-utils.c:545
statement freia_copy_image(const entity source, const entity target)
Definition: freia-utils.c:710
void hwac_kill_statement(statement s)
remove contents of statement s.
Definition: freia-utils.c:761
bool freia_image_variable_p(const entity var)
rather approximative?
Definition: freia-utils.c:768
int freia_max_pixel_value(void)
Definition: freia-utils.c:594
const freia_api_t * get_freia_api(int index)
Definition: freia-utils.c:477
bool same_constant_parameters(const dagvtx v1, const dagvtx v2)
tell whether v1 and v2 point to statements with the same parameters.
Definition: freia-utils.c:1014
bool freia_extract_kernel_vtx(dagvtx v, bool strict, intptr_t *k00, intptr_t *k10, intptr_t *k20, intptr_t *k01, intptr_t *k11, intptr_t *k21, intptr_t *k02, intptr_t *k12, intptr_t *k22)
vertex-based version
Definition: freia-utils.c:2012
call freia_statement_to_call(const statement s)
return the actual function call from a statement, dealing with assign and returns....
Definition: freia-utils.c:973
string what_operation(const _int type)
Definition: freia-utils.c:499
string what_operation_shape(const _int type)
SPoC: set shape depending on hardware component used by vertex.
Definition: freia-utils.c:518
bool freia_scalar_rw_dep(const statement s, const statement t, list *vars)
Definition: freia-utils.c:929
int hwac_freia_api_index(const string function)
returns the index of the description of an AIPO function
Definition: freia-utils.c:471
expression freia_get_nth_scalar_param(const dagvtx v, int n)
Definition: freia-utils.c:589
#define FREIA_IMAGE_TYPE
Definition: freia.h:46
#define cat(args...)
Definition: freia.h:41
#define AIPO
Definition: freia.h:51
#define sb_cat(args...)
Definition: freia.h:42
#define FREIA_FREE
Definition: freia.h:49
#define FREIA_ALLOC
Definition: freia.h:48
#define dagvtx_freia_api(v)
Definition: freia.h:97
static void comment(string_buffer code, spoc_hardware_type hw, dagvtx v, int stage, int side, bool flip)
Definition: freia_spoc.c:52
@ spoc_type_mes
Definition: freia_spoc.h:179
@ spoc_type_nop
Definition: freia_spoc.h:174
@ spoc_type_oth
Definition: freia_spoc.h:173
@ spoc_type_alu
Definition: freia_spoc.h:177
#define pstatement_statement_p(x)
#define dagvtx_content(x)
#define vtxcontent_optype(x)
#define dag_outputs(x)
#define vtxcontent_out(x)
#define vtxcontent_opid(x)
#define pstatement_statement(x)
#define dag_inputs(x)
#define dagvtx_succs(x)
#define dagvtx_domain
newgen_dag_domain_defined
#define vtxcontent_inputs(x)
#define dag_vertices(x)
#define vtxcontent_source(x)
#define DAGVTX(x)
DAGVTX.
static hash_table erosion
global variable used by the dagvtx_terapix_priority function, because qsort does not allow to pass so...
#define gen_context_recurse(start, ctxt, domain_number, flt, rwt)
Definition: genC.h:285
#define CHUNK(x)
Definition: genC.h:90
#define CHUNKP(x)
Definition: genC.h:92
static int input(void)
void free(void *)
entity get_current_module_entity(void)
Get the entity of the current module.
Definition: static.c:85
void gen_recurse_stop(void *obj)
Tells the recursion not to go in this object.
Definition: genClib.c:3251
void gen_context_multi_recurse(void *o, void *context,...)
Multi-recursion with context function visitor.
Definition: genClib.c:3373
void gen_null2(__attribute__((unused)) void *u1, __attribute__((unused)) void *u2)
idem with 2 args, to please overpeaky compiler checks
Definition: genClib.c:2758
bool gen_true2(__attribute__((unused)) gen_chunk *u1, __attribute__((unused)) void *u2)
Definition: genClib.c:2785
void gen_null(__attribute__((unused)) void *unused)
Ignore the argument.
Definition: genClib.c:2752
bool gen_true(__attribute__((unused)) gen_chunk *unused)
Return true and ignore the argument.
Definition: genClib.c:2780
list gen_make_list(int domain,...)
Definition: list.c:851
void gen_fprint(FILE *out, string name, const list l, gen_string_func_t item_name)
Definition: list.c:873
list gen_list_head(list *lp, int n)
Definition: list.c:1015
list gen_nreverse(list cp)
reverse a list in place
Definition: list.c:304
void gen_remove(list *cpp, const void *o)
remove all occurences of item o from list *cpp, which is thus modified.
Definition: list.c:685
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
list gen_once(const void *vo, list l)
Prepend an item to a list only if it is not already in the list.
Definition: list.c:722
list gen_copy_seq(list l)
Copy a list structure.
Definition: list.c:501
size_t gen_length(const list l)
Definition: list.c:150
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
list gen_nconc(list cp1, list cp2)
physically concatenates CP1 and CP2 but do not duplicates the elements
Definition: list.c:344
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
bool gen_in_list_p(const void *vo, const list lx)
tell whether vo belongs to lx
Definition: list.c:734
#define FOREACH(_fe_CASTER, _fe_item, _fe_list)
Apply/map an instruction block on all the elements of a list.
Definition: newgen_list.h:179
#define CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
int gen_occurences(const void *vo, const list l)
count occurences of vo in l
Definition: list.c:746
void gen_list_patch(list l, const void *x, const void *y)
Replace all the reference to x in list l by a reference to y:
Definition: list.c:985
void gen_sort_list(list l, gen_cmp_func_t compare)
Sorts a list of gen_chunks in place, to avoid allocations...
Definition: list.c:796
bool gen_replace_in_list(list l, const void *s, const void *t)
substitute all item s by t in list l
Definition: list.c:634
sequence statement_sequence(statement)
Get the sequence of a statement sequence.
Definition: statement.c:1328
call statement_call(statement)
Get the call of a statement.
Definition: statement.c:1406
bool statement_sequence_p(statement)
Statement classes induced from instruction type.
Definition: statement.c:335
statement make_assign_statement(expression, expression)
Definition: statement.c:583
void insert_statement(statement, statement, bool)
This is the normal entry point.
Definition: statement.c:2570
hash_table hash_table_make(hash_key_type key_type, size_t size)
Definition: hash.c:294
void * hash_get(const hash_table htp, const void *key)
this function retrieves in the hash table pointed to by htp the couple whose key is equal to key.
Definition: hash.c:449
void hash_put(hash_table htp, const void *key, const void *val)
This functions stores a couple (key,val) in the hash table pointed to by htp.
Definition: hash.c:364
void hash_table_free(hash_table htp)
this function deletes a hash table that is no longer useful.
Definition: hash.c:327
bool hash_defined_p(const hash_table htp, const void *key)
true if key has e value in htp.
Definition: hash.c:484
void * hash_del(hash_table htp, const void *key)
this function removes from the hash table pointed to by htp the couple whose key is equal to key.
Definition: hash.c:439
#define src(name, suf)
HPFC by Fabien Coelho, May 1993 and later...
Definition: compile.c:41
string db_get_directory_name_for_module(const char *name)
returns the allocated and mkdir'ed directory for module name
Definition: lowlevel.c:150
#define pips_debug
these macros use the GNU extensions that allow variadic macros, including with an empty list.
Definition: misc-local.h:145
#define pips_user_warning
Definition: misc-local.h:146
#define asprintf
Definition: misc-local.h:225
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define pips_internal_error
Definition: misc-local.h:149
#define DUMMY_STRUCT_PREFIX
Definition: naming-local.h:87
#define TYPEDEF_PREFIX
Definition: naming-local.h:62
char * i2a(int)
I2A (Integer TO Ascii) yields a string for a given Integer.
Definition: string.c:121
string bool_to_string(bool)
Definition: string.c:243
#define HASH_MAP(k, v, code, ht)
Definition: newgen_hash.h:60
@ hash_pointer
Definition: newgen_hash.h:32
#define same_string_p(s1, s2)
set set_assign_list(set, const list)
assigns a list contents to a set all duplicated elements are lost
Definition: set.c:474
set set_del_element(set, const set, const void *)
Definition: set.c:265
set set_intersection(set, const set, const set)
Definition: set.c:229
struct _set_chunk * set
Definition: newgen_set.h:38
bool list_in_set_p(const list, const set)
Definition: set.c:201
list set_to_sorted_list(const set, gen_cmp_func_t)
Definition: set.c:447
set set_assign(set, const set)
Assign a set with the content of another set.
Definition: set.c:129
int set_size(const set)
returns the number of items in s.
Definition: set.c:359
set set_difference(set, const set, const set)
Definition: set.c:256
#define SET_FOREACH(type_name, the_item, the_set)
enumerate set elements in their internal order.
Definition: newgen_set.h:78
void set_free(set)
Definition: set.c:332
set set_clear(set)
Assign the empty set to s s := {}.
Definition: set.c:326
string set_to_string(string, const set, gen_string_func_t)
return allocated string for set s
Definition: set.c:513
bool set_belong_p(const set, const void *)
Definition: set.c:194
set set_union(set, const set, const set)
Definition: set.c:211
void set_fprint(FILE *, string, const set, gen_string_func_t)
print set s to file stream out.
Definition: set.c:524
@ set_pointer
Definition: newgen_set.h:44
set set_append_list(set, const list)
add list l items to set s, which is returned.
Definition: set.c:460
set set_make(set_type)
Create an empty set of any type but hash_private.
Definition: set.c:102
set set_add_element(set, const set, const void *)
Definition: set.c:152
void string_buffer_to_file(const string_buffer, FILE *)
put string buffer into file.
void string_buffer_free(string_buffer *)
free string buffer structure, also free string contents according to the dup field
Definition: string_buffer.c:82
string_buffer string_buffer_make(bool dup)
allocate a new string buffer
Definition: string_buffer.c:58
string(* gen_string_func_t)(const void *)
Definition: newgen_types.h:111
#define _intFMT
Definition: newgen_types.h:57
intptr_t _int
_INT
Definition: newgen_types.h:53
struct cons * list
Definition: newgen_types.h:106
int(* gen_cmp_func_t)(const void *, const void *)
Definition: newgen_types.h:114
int f(int off1, int off2, int n, float r[n], float a[n], float b[n])
Definition: offsets.c:15
static char * module
Definition: pips.c:74
static const char * prefix
static const char * opname(const char *s)
#define BITWISE_XOR_OPERATOR_NAME
#define ENTITY_ASSIGN_P(e)
#define POINT_TO_OPERATOR_NAME
Definition: ri-util-local.h:92
#define UNARY_MINUS_OPERATOR_NAME
#define BITWISE_AND_OPERATOR_NAME
const char * entity_user_name(entity e)
Since entity_local_name may contain PIPS special characters such as prefixes (label,...
Definition: entity.c:487
const char * entity_local_name(entity e)
entity_local_name modified so that it does not core when used in vect_fprint, since someone thought t...
Definition: entity.c:453
entity FindOrCreateEntity(const char *package, const char *local_name)
Problem: A functional global entity may be referenced without parenthesis or CALL keyword in a functi...
Definition: entity.c:1586
int compare_entities(const entity *pe1, const entity *pe2)
Comparison function for qsort.
Definition: entity.c:1328
entity local_name_to_top_level_entity(const char *n)
This function try to find a top-level entity from a local name.
Definition: entity.c:1450
static int init
Maximal value set for Fortran 77.
Definition: entity.c:320
const char * module_local_name(entity e)
Returns the module local user name.
Definition: entity.c:582
string safe_entity_name(entity e)
predicates and functions for entities
Definition: entity.c:433
bool expression_integer_value(expression e, intptr_t *pval)
Definition: eval.c:792
expression entity_to_expression(entity e)
if v is a constant, returns a constant call.
Definition: expression.c:165
bool expression_equal_p(expression e1, expression e2)
Syntactic equality e1==e2.
Definition: expression.c:1347
expression int_to_expression(_int i)
transform an int into an expression and generate the corresponding entity if necessary; it is not cle...
Definition: expression.c:1188
expression MakeUnaryCall(entity f, expression a)
Creates a call expression to a function with one argument.
Definition: expression.c:342
bool expression_reference_p(expression e)
Test if an expression is a reference.
Definition: expression.c:528
reference expression_reference(expression e)
Short cut, meaningful only if expression_reference_p(e) holds.
Definition: expression.c:1832
entity expression_to_entity(expression e)
just returns the entity of an expression, or entity_undefined
Definition: expression.c:3140
expression dereference_expression(expression e)
generate a newly allocated expression for *(e)
Definition: expression.c:3934
expression call_to_expression(call c)
Build an expression that call a function or procedure.
Definition: expression.c:309
type ultimate_type(type)
Definition: type.c:3466
bool formal_parameter_p(entity)
Definition: variable.c:1489
#define type_struct(x)
Definition: ri.h:2964
#define syntax_reference_p(x)
Definition: ri.h:2728
#define expression_domain
newgen_execution_domain_defined
Definition: ri.h:154
#define syntax_reference(x)
Definition: ri.h:2730
#define call_function(x)
Definition: ri.h:709
#define EXPRESSION_(x)
Definition: ri.h:1220
#define reference_variable(x)
Definition: ri.h:2326
#define basic_derived(x)
Definition: ri.h:640
#define ENTITY(x)
ENTITY.
Definition: ri.h:2755
#define statement_ordering(x)
Definition: ri.h:2454
#define type_variable(x)
Definition: ri.h:2949
#define entity_storage(x)
Definition: ri.h:2794
#define call_domain
newgen_callees_domain_defined
Definition: ri.h:58
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
#define reference_domain
newgen_range_domain_defined
Definition: ri.h:338
#define entity_undefined
Definition: ri.h:2761
#define expression_undefined
Definition: ri.h:1223
#define entity_name(x)
Definition: ri.h:2790
#define sequence_statements(x)
Definition: ri.h:2360
#define reference_indices(x)
Definition: ri.h:2328
#define call_arguments(x)
Definition: ri.h:711
#define entity_type(x)
Definition: ri.h:2792
#define statement_number(x)
Definition: ri.h:2452
#define expression_syntax(x)
Definition: ri.h:1247
#define variable_basic(x)
Definition: ri.h:3120
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
#define entity_initial(x)
Definition: ri.h:2796
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
char * strdup()
#define ifdebug(n)
Definition: sg.c:47
static size_t current
Definition: string.c:115
internally defined structure.
Definition: string_buffer.c:47
FI: I do not understand why the type is duplicated at the set level.
Definition: set.c:59
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
FREIA API function name -> SPoC hardware description (and others?)
Definition: freia.h:71
string function_name
Definition: freia.h:73
unsigned int arg_misc_in
Definition: freia.h:83
string compact_name
Definition: freia.h:75
unsigned int arg_img_out
Definition: freia.h:79
string commutator
Definition: freia.h:77
unsigned int arg_misc_out
Definition: freia.h:82
unsigned int arg_img_in
Definition: freia.h:80
code taken from http://fast-edge.googlecode.com and adapted to c99
Definition: erode_dilate.c:33
Definition: statement.c:4047
bool write
Definition: dag-utils.c:2699
entity old
Definition: dag-utils.c:2699
entity new
Definition: dag-utils.c:2699
static Panel_item choice
Definition: xv_schoose2.c:54