PIPS
freia_spoc.c
Go to the documentation of this file.
1 /*
2 
3  $Id: freia_spoc.c 23288 2016-11-08 10:09:39Z 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 #include "freia_spoc.h"
36 
37 #include "linear.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 // help reduce code size:
49 #define T true
50 #define F false
51 
53  dagvtx v, int stage, int side, bool flip)
54 {
55  sb_cat(code, " // ", what_operation(hw), " ",
56  i2a(dagvtx_number(v)), " ", dagvtx_operation(v));
57  sb_cat(code, " stage ", i2a(stage));
58  if (hw!=spoc_type_alu) sb_cat(code, " side ", i2a(side));
59  if (hw==spoc_type_alu && flip) sb_cat(code, " flipped");
60  sb_cat(code, "\n");
61 }
62 
63 /********************************************************* ALU CONFIGURATION */
64 
65 // value to set operation, in same order as enum declaration
66 static const spoc_alu_op_t ALU_OP[] = {
67  { alu_unused, alu_unused, NULL, F, F, F },
68  // ADD
69  { alu_add, alu_add, "SPOC_ALU_ADD_IN0_IN1", F, T, T },
70  { alu_add_0cst, alu_add_1cst, "SPOC_ALU_ADD_IN0_CONST", T, T, F },
71  { alu_add_1cst, alu_add_0cst, "SPOC_ALU_ADD_IN1_CONST", T, F, T },
72  // ADDSAT
73  { alu_addsat, alu_addsat, "SPOC_ALU_ADDSAT_IN0_IN1", F, T, T },
74  { alu_addsat_0cst, alu_addsat_1cst, "SPOC_ALU_ADDSAT_IN0_CONST", T, T, F },
75  { alu_addsat_1cst, alu_addsat_0cst, "SPOC_ALU_ADDSAT_IN1_CONST", T, F, T },
76  // SUB
77  { alu_sub_01, alu_sub_10, "SPOC_ALU_SUB_IN0_IN1", F, T, T },
78  { alu_sub_10, alu_sub_01, "SPOC_ALU_SUB_IN1_IN0", F, T, T },
79  { alu_sub_0cst, alu_sub_1cst, "SPOC_ALU_SUB_IN0_CONST", T, T, F },
80  { alu_sub_1cst, alu_sub_0cst, "SPOC_ALU_SUB_IN1_CONST", T, F, T },
81  { alu_sub_cst0, alu_sub_cst1, "SPOC_ALU_SUB_CONST_IN0", T, T, F },
82  { alu_sub_cst1, alu_sub_cst0, "SPOC_ALU_SUB_CONST_IN1", T, F, T },
83  // SUBSAT
84  { alu_subsat_01, alu_subsat_10, "SPOC_ALU_SUBSAT_IN0_IN1", F, T, T },
85  { alu_subsat_10, alu_subsat_01, "SPOC_ALU_SUBSAT_IN1_IN0", F, T, T },
86  { alu_subsat_0cst, alu_subsat_1cst, "SPOC_ALU_SUBSAT_IN0_CONST", T, T, F },
87  { alu_subsat_1cst, alu_subsat_0cst, "SPOC_ALU_SUBSAT_IN1_CONST", T, F, T },
88  { alu_subsat_cst0, alu_subsat_cst1, "SPOC_ALU_SUBSAT_CONST_IN0", T, T, F },
89  { alu_subsat_cst1, alu_subsat_cst0, "SPOC_ALU_SUBSAT_CONST_IN1", T, F, T },
90  // ABSSUB
91  { alu_abssub, alu_abssub, "SPOC_ALU_ABSSUB_IN0_IN1", F, T, T },
92  { alu_abssub_0cst, alu_abssub_1cst, "SPOC_ALU_ABSSUB_IN0_CONST", T, T, F },
93  { alu_abssub_1cst, alu_abssub_0cst, "SPOC_ALU_ABSSUB_IN1_CONST", T, F, T },
94  // MUL
95  { alu_mul, alu_mul, "SPOC_ALU_MUL_IN0_IN1", F, T, T },
96  { alu_mul_0cst, alu_mul_1cst, "SPOC_ALU_MUL_IN0_CONST", T, T, F },
97  { alu_mul_1cst, alu_mul_0cst, "SPOC_ALU_MUL_IN1_CONST", T, F, T },
98  // DIV
99  { alu_div_01, alu_div_10, "SPOC_ALU_DIV_IN0_IN1", F, T, T },
100  { alu_div_10, alu_div_01, "SPOC_ALU_DIV_IN1_IN0", F, T, T },
101  { alu_div_0cst, alu_div_1cst, "SPOC_ALU_DIV_IN0_CONST", T, T, F },
102  { alu_div_1cst, alu_div_0cst, "SPOC_ALU_DIV_IN1_CONST", T, F, T },
103  { alu_div_cst0, alu_div_cst1, "SPOC_ALU_DIV_CONST_IN0", T, T, F },
104  { alu_div_cst1, alu_div_cst0, "SPOC_ALU_DIV_CONST_IN1", T, F, T },
105  // LOG2
106  { alu_log2_0, alu_log2_1, "SPOC_ALU_LOG2_IN0", F, T, F },
107  { alu_log2_1, alu_log2_0, "SPOC_ALU_LOG2_IN1", F, F, T },
108  // INF
109  { alu_inf_01, alu_inf_01, "SPOC_ALU_INF_IN0_IN1", F, T, T },
110  { alu_inf_0cst, alu_inf_1cst, "SPOC_ALU_INF_IN0_CONST", T, T, F },
111  { alu_inf_1cst, alu_inf_0cst, "SPOC_ALU_INF_IN1_CONST", T, F, T },
112  // SUP
113  { alu_sup_01, alu_sup_01, "SPOC_ALU_SUP_IN0_IN1", F, T, T },
114  { alu_sup_0cst, alu_sup_1cst, "SPOC_ALU_SUP_IN0_CONST", T, T, F },
115  { alu_sup_1cst, alu_sup_0cst, "SPOC_ALU_SUP_IN1_CONST", T, F, T },
116  // AND
117  { alu_and, alu_and, "SPOC_ALU_AND_IN0_IN1", F, T, T },
118  { alu_and_0cst, alu_and_1cst, "SPOC_ALU_AND_IN0_CONST", T, T, F },
119  { alu_and_1cst, alu_and_0cst, "SPOC_ALU_AND_IN1_CONST", T, F, T },
120  // OR
121  { alu_or, alu_or, "SPOC_ALU_OR_IN0_IN1", F, T, T },
122  { alu_or_0cst, alu_or_1cst, "SPOC_ALU_OR_IN0_CONST", T, T, F },
123  { alu_or_1cst, alu_or_0cst, "SPOC_ALU_OR_IN1_CONST", T, F, T },
124  // XOR
125  { alu_xor, alu_xor, "SPOC_ALU_XOR_IN0_IN1", F, T, T },
126  { alu_xor_0cst, alu_xor_1cst, "SPOC_ALU_XOR_IN0_CONST", T, T, F },
127  { alu_xor_1cst, alu_xor_0cst, "SPOC_ALU_XOR_IN1_CONST", T, F, T },
128  // NOT
129  { alu_not_0, alu_not_1, "SPOC_ALU_NOT_IN0", F, T, F },
130  { alu_not_1, alu_not_0, "SPOC_ALU_NOT_IN1", F, F, T },
131  // MISC
132  { alu_copy_cst, alu_copy_cst, "SPOC_ALU_COPY_CONST", T, F, F },
133  { alu_mask_0, alu_mask_1, "SPOC_ALU_MASK_IN0_IN1", F, T, T },
134  { alu_mask_1, alu_mask_0, "SPOC_ALU_MASK_IN1_IN0", F, T, T },
135  // hmmm, the input images are exchanged from AIPO to SPOC?
136  { alu_repcst_0, alu_repcst_1, "SPOC_ALU_REPLACE_IN1_IN0_CONST", T, T, T },
137  { alu_repcst_1, alu_repcst_0, "SPOC_ALU_REPLACE_IN0_IN1_CONST", T, T, T }
138  // and so on?
139 };
140 
142 {
143  return &ALU_OP[alu];
144 }
145 
146 /* generate a configuration for the ALU hardware component.
147  */
148 static void spoc_alu_conf
149  (spoc_alu_t alu,
150  string_buffer body,
151  __attribute__ ((__unused__)) string_buffer tail,
152  int stage,
153  bool flip,
154  dagvtx orig,
155  hash_table hp)
156 {
157  if (alu!=alu_unused) // should not be called? copy?
158  {
159  if (flip) // only flip if distinct
160  {
161  spoc_alu_t flipped_alu = get_spoc_alu_conf(alu)->flipped;
162  if (alu!=flipped_alu)
163  alu = flipped_alu;
164  else
165  flip = false;
166  }
167  const spoc_alu_op_t * aluop = get_spoc_alu_conf(alu);
168  message_assert("alu operation found", alu==aluop->op);
169 
170  string s_stage = strdup(i2a(stage));
171  comment(body, spoc_type_alu, orig, stage, -1, flip);
172  sb_cat(body, " si.alu[", s_stage, "][0].op = ", aluop->setting, ";\n");
173  if (aluop->use_cst)
174  {
176  string s_var = hash_get(hp, arg);
177  // res += "spocinstr.alu[%stage][0].constant = " + var + ";\n";
178  sb_cat(body, " sp.alu[", s_stage, "][0].constant = ", s_var, ";\n");
179  }
180 
181  free(s_stage);
182  }
183 }
184 
185 /***************************************** POC & TH & MEASURE CONFIGURATIONS */
186 
187 /* generate a configuration for a POC (morpho) hardware component.
188  */
189 static void spoc_poc_conf
190  (spoc_poc_t poc,
191  string_buffer body,
192  __attribute__ ((__unused__)) string_buffer tail,
193  int stage,
194  int side,
195  dagvtx orig,
196  hash_table hp) // expression -> parameter name
197 {
198  if (poc.op!=spoc_poc_unused) // should not be called?
199  {
200  string
201  s_stag = strdup(i2a(stage)),
202  s_side = strdup(i2a(side));
203 
204  // only one argument is expected, the kernel
206  string s_var = hash_get(hp, arg);
207 
208  // spocinstr.poc[0][0].op = SPOC_POC_ERODE;
209  comment(body, spoc_type_poc, orig, stage, side, false);
210  sb_cat(body, " si.poc[", s_stag, "][", s_side, "].op = ");
211  if (poc.op==spoc_poc_erode)
212  sb_cat(body, "SPOC_POC_ERODE;\n");
213  else if (poc.op==spoc_poc_dilate)
214  sb_cat(body, "SPOC_POC_DILATE;\n");
215  else if (poc.op==spoc_poc_conv)
216  sb_cat(body, "SPOC_POC_CONV;\n");
217  else
218  pips_internal_error("unexpected poc operation %d", poc.op);
219 
220  // spocinstr.poc[0][0].grid = SPOC_POC_8_CONNEX;
221  sb_cat(body, " si.poc[", s_stag, "][", s_side, "].grid = ");
222  if (poc.connectivity==6)
223  sb_cat(body, "SPOC_POC_6_CONNEX;\n");
224  else if (poc.connectivity==8)
225  sb_cat(body, "SPOC_POC_8_CONNEX;\n");
226  else
227  pips_internal_error("unexpected poc connectivity %d", poc.connectivity);
228 
229  // for(i=0 ; i<9 ; i++) spocparam.poc[0][0].kernel[i] = kernel[i];
230  sb_cat(body,
231  " for(i=0 ; i<9 ; i++)\n"
232  " sp.poc[", s_stag, "][", s_side, "].kernel[i] = ",
233  s_var, "[i];\n");
234 
235  free(s_stag);
236  free(s_side);
237  }
238 }
239 
240 /* generate a configuration for a threshold component.
241  */
242 static void spoc_th_conf
243  (string_buffer body,
244  __attribute__ ((__unused__)) string_buffer tail,
245  int stage,
246  int side,
247  dagvtx orig,
248  hash_table hp)
249 {
250  list largs = freia_get_vertex_params(orig);
251  pips_assert("3 arguments to threshold", gen_length(largs)==3);
252  expression
253  e_inf = EXPRESSION(CAR(largs)),
254  e_sup = EXPRESSION(CAR(CDR(largs))),
255  e_bin = EXPRESSION(CAR(CDR(CDR(largs))));
256  string
257  s_inf = hash_get(hp, e_inf),
258  s_sup = hash_get(hp, e_sup),
259  s_bin = hash_get(hp, e_bin),
260  s_stag = strdup(i2a(stage)),
261  s_side = strdup(i2a(side));
262 
263  // spocinstr.th[0][0].op =
264  // (binarize==true) ? SPOC_TH_BINARIZE : SPOC_TH_NO_BINARIZE;
265  // spocparam.th[0][0].boundmin = boundinf;
266  // spocparam.th[0][0].boundmax = boundsup;
267  comment(body, spoc_type_thr, orig, stage, side, false);
268  sb_cat(body,
269  " si.th[", s_stag, "][", s_side, "].op = ",
270  s_bin, "? SPOC_TH_BINARIZE : SPOC_TH_NO_BINARIZE;\n",
271  " sp.th[", s_stag, "][", s_side, "].boundmin = ", s_inf, ";\n",
272  " sp.th[", s_stag, "][", s_side, "].boundmax = ", s_sup, ";\n");
273 
274  free(s_stag);
275  free(s_side);
276 }
277 
279 {
280  switch (measure)
281  {
282  case measure_none:
283  return 0;
284  case measure_max_coord:
285  case measure_min_coord:
286  return 3;
287  default:
288  return 1;
289  }
290 }
291 
292 /* there is no real configuration for the measures,
293  * the issue is just to fetch them.
294  */
295 static void spoc_measure_conf
296  (spoc_measure_t measure,
297  __attribute__ ((__unused__)) string_buffer body,
298  string_buffer tail,
299  int stage,
300  int side,
301  dagvtx orig,
302  hash_table hp)
303 {
304  int n = spoc_measure_n_params(measure);
305  if (n==0) return;
306  pips_assert("1 to 3 parameters", n>=1 && n<=3);
307 
308  string
309  s_stage = strdup(i2a(stage)),
310  s_side = strdup(i2a(side)),
311  reduc = strdup(cat("reduc.measure[", s_stage, "][", s_side, "]."));
312 
313  list largs = freia_get_vertex_params(orig);
314 
315  pips_assert("argument list length is okay", (int) gen_length(largs)==n);
316 
317  string
318  v_1 = hash_get(hp, EXPRESSION(CAR(largs))),
319  v_2 = NULL, v_3 = NULL;
320  if (n>=2) v_2 = hash_get(hp, EXPRESSION(CAR(CDR(largs))));
321  if (n>=3) v_3 = hash_get(hp, EXPRESSION(CAR(CDR(CDR(largs)))));
322 
323  sb_cat(tail, "\n");
324  comment(tail, spoc_type_mes, orig, stage, side, false);
325 
326  switch (measure) {
327  case measure_max:
328  case measure_min:
329  case measure_max_coord:
330  case measure_min_coord:
331  sb_cat(tail, " *", v_1, " = (int32_t) ", reduc,
332  measure==measure_min||measure==measure_min_coord?
333  "minimum": "maximum", ";\n");
334  if (n>1)
335  {
336  sb_cat(tail, " *", v_2, " = (uint32_t) ", reduc,
337  measure==measure_min||measure==measure_min_coord?
338  "min": "max", "_coord_x;\n",
339  " *", v_3, " = (uint32_t) ", reduc,
340  measure==measure_min||measure==measure_min_coord?
341  "min": "max", "_coord_y;\n");
342  }
343  break;
344  case measure_vol:
345  sb_cat(tail, " *", v_1, " = (int32_t) ", reduc, "volume;\n");
346  break;
347  default:
348  pips_internal_error("unexpected measure %d", measure);
349  }
350 
351  free(s_stage);
352  free(s_side);
353  free(reduc);
354 }
355 
356 /* basic configuration generation for a stage, depending on hw description
357  * @returns the number of arguments expected?
358  * what about their type?
359  */
360 static void basic_spoc_conf
361  (spoc_hardware_type op,
362  string_buffer body,
363  string_buffer tail,
364  int stage,
365  int side,
366  bool flip,
367  const spoc_hw_t * conf,
368  dagvtx orig,
369  hash_table hp)
370 {
371  // only one call should be used for AIPO functions ?
372  switch (op) {
373  case spoc_type_poc:
374  spoc_poc_conf(conf->poc[0], body, tail, stage, side, orig, hp);
375  break;
376  case spoc_type_alu:
377  spoc_alu_conf(conf->alu, body, tail, stage, flip, orig, hp);
378  break;
379  case spoc_type_thr:
380  spoc_th_conf(body, tail, stage, side, orig, hp);
381  break;
382  case spoc_type_mes:
383  spoc_measure_conf(conf->mes[0], body, tail, stage, side, orig, hp);
384  break;
385  case spoc_type_inp:
386  case spoc_type_nop:
387  // copy, no code
388  break;
389  default:
390  pips_internal_error("unexpected op type %s", what_operation(op));
391  }
392  if (op!=spoc_type_nop)
393  sb_cat(body, "\n");
394 }
395 
396 /* a data structure to describe a schedule for an operation
397  */
398 typedef struct {
399  entity image; // output of this operation
400  dagvtx producer; // possibly NULL on input and output
401  int stage; // stage of production
402  spoc_hardware_type level; // nope | input < poc < alu < threshold < measure
403  int side; // 0 or 1
404  bool flip; // whether alu op is flipped
405  bool used; // whether the image has been used by an output
406  bool just_used; // idem but at this stage
407  // where this was used, to detect some particular cases?
410 } op_schedule;
411 
412 static void init_op_schedule(op_schedule * op, dagvtx v, int side)
413 {
414  op->image = v? dagvtx_image(v): NULL;
415  op->producer = v;
416  op->stage = 0;
417  op->level = spoc_type_inp;
418  op->side = side;
419  op->flip = false;
420  op->used = false;
421  op->just_used = false;
422  op->used_stage = -1; // never used
424 }
425 
426 static int max_stage(const op_schedule * in0, const op_schedule * in1)
427 {
428  if (in0->image)
429  if (in1->image)
430  // both
431  return (in0->stage > in1->stage)? in0->stage: in1->stage;
432  else
433  // only in0
434  return in0->stage;
435  else
436  if (in1->image)
437  // only in1
438  return in1->stage;
439  else
440  // none
441  return 0;
442 }
443 
444 /* is image needed?
445  */
446 static bool image_is_needed(dagvtx prod, dag d, set todo)
447 {
448  bool needed = false;
449  if (prod)
450  {
451  if (gen_in_list_p(prod, dag_outputs(d)))
452  needed = true;
453  else
454  {
455  SET_FOREACH(dagvtx, v, todo)
456  {
457  list preds = dag_vertex_preds(d, v);
458  needed = gen_in_list_p(prod, preds);
459  gen_free_list(preds), preds = NIL;
460  if (needed)
461  break;
462  }
463  }
464  pips_debug(7, "\"%"_intFMT"\" is%s needed\n",
465  dagvtx_number(prod), needed? "": " not");
466  }
467  return needed;
468 }
469 
470 // debug
471 static void
472 print_op_schedule(FILE * out, const string name, const op_schedule * op)
473 {
474  fprintf(out, "sched '%s' = %s (%" _intFMT " %s) %d:%s:%d %s %sused (%d:%s)\n",
475  name,
476  op->image? entity_local_name(op->image): "NULL",
477  dagvtx_number(op->producer),
479  op->stage, what_operation(op->level), op->side,
480  (op->level==spoc_type_alu)? (op->flip? "/": "."): "",
481  op->used? "": "not ",
483 }
484 
485 static bool check_mux_availibity(hash_table wiring, int stage, int mux)
486 {
487  _int index = 2 * (stage*4+mux) + 1; // odds
488  return !hash_defined_p(wiring, (void *) index);
489 }
490 
491 static void set_mux(hash_table wiring, int stage, int mux)
492 {
493  _int index = 2 * (stage*4+mux) + 1; // odds
494  hash_put(wiring, (void *) index, (void *) index);
495 }
496 
497 /* can I get out of stage on this side?
498  */
499 static bool check_wiring_output(hash_table wiring, int stage, int side)
500 {
501  return check_mux_availibity(wiring, stage, side? 3: 0);
502 }
503 
504 static _int component_index(int stage, int level, int side)
505 {
506  pips_assert("spoc component", level>=spoc_type_poc && level<= spoc_type_mes);
507  if (level==spoc_type_alu) side=0;
508  return 2 * (2 * (stage*4+level) + side) + 2; // even
509 }
510 
511 static void set_component(hash_table wiring, int stage, int level, int side)
512 {
513  _int index = component_index(stage, level, side);
514  hash_put(wiring, (void *) index, (void *) index);
515  // scratch everything on the path before the used component
516  if (stage>0 && level==spoc_type_poc)
517  set_component(wiring, stage-1, spoc_type_mes, side);
518  if (level==spoc_type_mes)
519  set_component(wiring, stage, spoc_type_thr, side);
520 }
521 
523  (hash_table wiring, int stage, int level, int side)
524 {
525  _int index = component_index(stage, level, side);
526  return !hash_defined_p(wiring, (void *) index);
527 }
528 
529 /* return the first stage after stage/level with both paths available
530  */
531 static int find_first_crossing(hash_table wiring, int stage, int level)
532 {
533  if (level>spoc_type_alu)
534  stage++;
535  while (!(check_wiring_output(wiring, stage, 0) &&
536  check_wiring_output(wiring, stage, 1)))
537  stage++;
538  return stage;
539 }
540 
541 /* return the stage & side of the first component available
542  * after (start_stage, level, side) which is the source of the used image,
543  * for an operation of type target_level
544  */
546  hash_table wiring,
547  int start_stage, int level, int side, // image comes from
548  int target_level,
549  bool crossing, // whether to include a crossing on the path...
550  int * pstage, int * pside)
551 {
552  int stage = start_stage;
553  int preferred, other;
554  if (side>=0) preferred = side, other = 1 - side;
555  // side==-1, alu...
556  else preferred = 0, other = 1;
557  if (target_level==spoc_type_alu)
558  preferred=0, other=0;
559 
560  if (target_level<=level)
561  stage++;
562 
563  if (crossing)
564  {
565  stage = find_first_crossing(wiring, stage, level);
566  if (target_level<spoc_type_alu)
567  stage++;
568  }
569 
570  bool pok,
571  skip_first_other =
572  (stage==start_stage && target_level<spoc_type_alu) ||
573  (stage==start_stage+1 && target_level<spoc_type_alu && level>spoc_type_alu);
574 
575  while (!(pok=available_component(wiring, stage, target_level, preferred)) &&
576  (skip_first_other ||
577  !available_component(wiring, stage, target_level, other)))
578  {
579  stage++;
580  skip_first_other = false;
581  }
582 
583  // hmmm...
584  if (pok && level<=spoc_type_alu &&
585  stage==start_stage+1 && target_level<spoc_type_alu)
586  {
587  if (!check_wiring_output(wiring, start_stage, preferred))
588  {
589  pips_assert("symmetric component must be available",
590  available_component(wiring, stage, target_level, other));
591  pok = false;
592  }
593  }
594 
595  // return result
596  *pstage = stage;
597  *pside = pok? preferred: other;
598 }
599 
600 /* generate wiring code for mux if necessary.
601  * @param code generated
602  * @param stage stage under consideration
603  * @param mux multiplexer to set
604  * @param value status for the multiplexer
605  * @param wiring already performed wiring to check for double settings.
606  */
607 static void
609  int stage, // 0 ..
610  int mux, // 0 to 3
611  _int value, // 0 1
612  hash_table wiring)
613 {
614  pips_debug(8, "%d %d %"_intFMT"\n", stage, mux, value);
615 
616  pips_assert("mux is available", check_mux_availibity(wiring, stage, mux));
617 
618  // code
619  string s_stage = strdup(i2a(stage)), s_mux = strdup(i2a(mux));
620  sb_cat(code, " si.mux[", s_stage, "][", s_mux, "].op = "
621  "SPOC_MUX_IN", value? "1": "0", ";\n");
622  free(s_stage);
623  free(s_mux);
624 
625  // record
626  set_mux(wiring, stage, mux);
627 }
628 
629 /* depending on available images (stage %d, level, side 0/1)
630  * and vertex operation to perform , tell where to perform it.
631  * some voodoo again...
632  */
633 static void
635  (const dagvtx op,
636  op_schedule * in0,
637  op_schedule * in1,
638  dag computed, // current computed dag
639  set todo, // vertices still to be computed
640  op_schedule * out,
641  hash_table wiring)
642 {
643  vtxcontent c = dagvtx_content(op);
644  out->side = -100;
645  out->used = false;
646  out->used_stage = -1;
647  out->used_level = spoc_type_inp;
648  in0->just_used = false;
649  in1->just_used = false;
650 
651  ifdebug(6) {
652  pips_debug(6, "scheduling (%" _intFMT " %s) %s\n",
656  print_op_schedule(stderr, "in0", in0);
657  print_op_schedule(stderr, "in1", in1);
658  }
659 
661 
662  // measurements is special case, because the image is not consummed...
663  if (level == spoc_type_mes)
664  {
665  pips_assert("one input image", gen_length(vtxcontent_inputs(c))==1);
666  entity measured = ENTITY(CAR(vtxcontent_inputs(c)));
667  pips_assert("input image available",
668  measured==in0->image || measured==in1->image);
669  // go to the end of the stage of the image producer,
670  // on same side...
671  if (in0->image == in1->image)
672  {
673  // we have the same image, chose closest to mes, and prefer in0
674  if (in0->level>=in1->level)
675  *out = *in0, in0->used = (in0->level!=spoc_type_mes),
676  in0->just_used = true, in1->used = false;
677  else
678  *out = *in1, in1->used = (in0->level!=spoc_type_mes),
679  in1->just_used = true, in0->used = false;
680  }
681  else // take the available one, whatever
682  {
683  if (measured==in0->image)
684  *out = *in0, in0->used = (in0->level!=spoc_type_mes),
685  in0->just_used = true, in1->used = false;
686  else
687  *out = *in1, in1->used = (in0->level!=spoc_type_mes),
688  in1->just_used = true, in0->used = false;
689  }
690  }
691  else
692  {
693  // how many images (arguments) are needed by the operation?
694  int needed = (int) gen_length(vtxcontent_inputs(c));
695  switch (needed)
696  {
697  case 0: // ALU CONST GENERATION ?
698  pips_assert("alu const image generation", level==spoc_type_alu);
699  // I must check that the alu is not already used?!
700  // So I take a safe bet...
701  // ??? argh... the image may have been cleaned of not used any more...
702  out->stage = max_stage(in0, in1);
703 
704  // hmmm... I should also check that the component is not already used...
705  if (in0->image && in0->stage == out->stage && in0->level >= spoc_type_alu)
706  out->stage++;
707  if (in1->image && in1->stage == out->stage && in1->level >= spoc_type_alu)
708  out->stage++;
709 
710  // ensure there is at least one path for the output
711  while (!(check_wiring_output(wiring, out->stage, 0) ||
712  check_wiring_output(wiring, out->stage, 1)))
713  out->stage++;
714 
715  // two paths are required if one of the other image is still needed.
716  if ((in0->image && image_is_needed(in0->producer, computed, todo)) ||
717  (in1->image && image_is_needed(in1->producer, computed, todo)))
718  {
719  while (! (check_wiring_output(wiring, out->stage, 0) &&
720  check_wiring_output(wiring, out->stage, 1)))
721  out->stage++;
722  }
723 
724  in0->used = false, in1->used = false;
725  break;
726  case 1: // ANYTHING, may have to chose a side.
727  {
728  entity dep = ENTITY(CAR(vtxcontent_inputs(c)));
729  pips_assert("dependence is available",
730  dep==in0->image || dep==in1->image);
731  op_schedule * used, * notused;
732 
733  // where is the needed image? put it in used
734  if (in0->image == in1->image)
735  {
736  // if the same image is available,
737  // chose the not already used one
738  if (in0->used)
739  used = in1, notused = in0;
740  else if (in0->used)
741  used = in0, notused = in1;
742  // or the one which is already engaged on a side?
743  else if (in0->level >= spoc_type_thr && level <= spoc_type_alu)
744  used = in0, notused = in1;
745  else if (in1->level >= spoc_type_thr && level <= spoc_type_alu)
746  used = in1, notused = in0;
747  // or the earliest one, or in0 by default
748  else if (in1->stage<in0->stage ||
749  (in1->stage==in0->stage && in1->level < in0->level))
750  used = in1, notused = in0;
751  else
752  used = in0, notused = in1;
753  }
754  else // just take the right one
755  {
756  used = dep==in0->image? in0: in1;
757  notused = dep==in0->image? in1: in0;
758  }
759 
760  pips_debug(7, "using %s (%d %s %d)\n",
761  entity_local_name(used->image),
762  used->stage, what_operation(used->level), used->side);
763 
764  // default stage and side...
765  out->stage = used->stage;
766  out->side = used->side;
767  used->used = true;
768  used->just_used = true;
769 
770  bool used_image_still_needed =
771  image_is_needed(used->producer, computed, todo);
772 
773  // handle copy... if it is still there, it must be needed,
774  // so just put it where it is available for later use.
775  // ??? output copies should not be handled by the pipeline!
776  if (level == spoc_type_nop)
777  {
778  // go to the end of the local path
779  switch (used->level)
780  {
781  case spoc_type_inp:
782  case spoc_type_poc:
784  break;
785  case spoc_type_alu:
787  break;
788  case spoc_type_thr:
789  case spoc_type_mes:
791  out->stage++;
792  break;
793  default:
794  pips_internal_error("unexpected spoc type %d", used->level);
795  }
796 
797  // we need to put some space to extract the other image on another path
798  if (used_image_still_needed)
799  {
800  if (level==spoc_type_poc)
801  {
802  // switch side if straight path is not available?
803  if (!check_wiring_output(wiring, out->stage, out->side))
804  out->side = 1 - out->side;
805  pips_assert("available path",
806  check_wiring_output(wiring, out->stage, out->side));
807  out->stage++;
808  }
809  else if (level==spoc_type_alu)
810  {
811  // choose one side, prefer 0
812  if (check_wiring_output(wiring, out->stage, 0))
813  out->side = 0;
814  else if (check_wiring_output(wiring, out->stage, 1))
815  out->side = 1;
816  else
817  pips_internal_error("no available path for copy of needed image");
818  out->stage++;
820  }
821  else
822  pips_internal_error("should not get there");
823  }
824  else
825  pips_debug(8, "copied image %s is not needed further\n",
826  entity_local_name(used->image));
827  break;
828  }
829 
830  pips_assert("not a copy", level!=spoc_type_nop);
831 
832  // ??? hmmm... an ALU used the operation???
834  (wiring,
835  // source (level may be shifted for ALU/morph issue, see freia_50
836  used->stage,
837  used->used_stage!=-1 &&
838  used->used_level==spoc_type_alu &&
839  level==spoc_type_poc? spoc_type_poc: used->level, used->side,
840  level, used_image_still_needed && used->image!=notused->image,
841  &out->stage, &out->side);
842 
843  // tell which image was used
844  used->used = true;
845  notused->used = false;
846 
847  // record last use
848  used->used_stage = out->stage;
849  used->used_level = level;
850  break;
851  }
852  case 2: // ALU
853  // what if same image is used as both operands?
854  if (!in1->image) *in1 = *in0;
855  if (!in0->image) *in0 = *in1;
856  pips_assert("alu binary operation", level==spoc_type_alu);
857  out->stage = max_stage(in0, in1);
858  // update input image status
859  in0->used = true, in0->just_used = true;
860  in1->used = true, in1->just_used = true;
861  if (out->stage==in0->stage && in0->level >= spoc_type_alu)
862  out->stage++;
863  if (out->stage==in1->stage && in1->level >= spoc_type_alu)
864  out->stage++;
865  // including where last used
866  in0->used_stage = out->stage;
867  in0->used_level = level;
868  in1->used_stage = out->stage;
869  in1->used_level = level;
870  break;
871  default:
872  pips_internal_error("shoud not get there");
873  }
874  }
875 
876  // common settings
877  out->level = level;
878  if (out->level == spoc_type_alu)
879  out->side = -1;
880  else if (out->side==-1)
881  {
882  // must set a size if not already chosen
883  int stage = out->level<spoc_type_alu? out->stage-1: out->stage;
884  if (check_wiring_output(wiring, stage, 0))
885  out->side = 0;
886  else if (check_wiring_output(wiring, stage, 1))
887  out->side = 1;
888  else
889  pips_internal_error("no available path");
890  }
891 
893  {
894  out->image = vtxcontent_out(c);
895  out->producer = op;
896  }
897  // else it is a measure, don't change...
898  ifdebug(6) print_op_schedule(stderr, "out", out);
899 }
900 
901 /* all possible wirings at one stage
902  */
905  int stage,
906  int in_side, // 0, 1, -1 for "alu"...
907  int out_side,
908  hash_table wiring)
909 {
910  pips_assert("check sides",
911  in_side>=-1 && in_side<=1 && out_side>=0 && out_side<=1);
912  pips_debug(7, "stage %d in %d -> out %d\n", stage, in_side, out_side);
913  switch (in_side)
914  {
915  case -1:
916  if (out_side) {
917  set_wiring(code, stage, 1, 1, wiring);
918  set_wiring(code, stage, 3, 0, wiring);
919  }
920  else {
921  set_wiring(code, stage, 0, 1, wiring);
922  set_wiring(code, stage, 2, 0, wiring);
923  }
924  break;
925  case 0:
926  if (out_side) {
927  set_wiring(code, stage, 1, 0, wiring);
928  set_wiring(code, stage, 3, 0, wiring);
929  }
930  else
931  set_wiring(code, stage, 0, 0, wiring);
932  break;
933  case 1:
934  if (out_side)
935  set_wiring(code, stage, 3, 1, wiring);
936  else {
937  set_wiring(code, stage, 0, 1, wiring);
938  set_wiring(code, stage, 2, 1, wiring);
939  }
940  break;
941  default:
942  pips_internal_error("should not get there...");
943  }
944 }
945 
946 /* generate wire code from in to out, record choices in wiring.
947  */
948 static void generate_wiring
950  op_schedule * in,
951  op_schedule * out,
952  hash_table wiring)
953 {
954  pips_debug(6, "%s [%d %s %d] -> [%d %s %d] %" _intFMT "\n",
956  in->stage, what_operation(in->level), in->side,
957  out->stage, what_operation(out->level), out->side,
958  dagvtx_number(out->producer));
959 
960  pips_assert("ordered schedule",
961  (in->stage < out->stage) ||
962  ((in->stage == out->stage) && (in->level <= out->level)));
963 
964  // code comment...
965  string
966  in_stage = strdup(i2a(in->stage)),
967  out_stage = strdup(i2a(out->stage)),
968  in_side = strdup(i2a(in->side)),
969  out_side = strdup(i2a(out->side));
970 
971  sb_cat(code,
972  " // ", entity_local_name(in->image),
973  " [", in_stage, " ", what_operation(in->level));
974  if (in->level!=spoc_type_alu)
975  sb_cat(code, " ", in_side);
976  sb_cat(code, "] -> [", out_stage, " ", what_operation(out->level));
977  if (out->level!=spoc_type_alu)
978  sb_cat(code, " ", out_side);
979  sb_cat(code, "] ", i2a(dagvtx_number(out->producer)), " ",
980  dagvtx_operation(out->producer), "\n");
981  free(in_stage); free(out_stage); free(in_side); free(out_side);
982 
983  // let us wire!
984  if (in->stage==out->stage)
985  {
986  switch (in->level)
987  {
988  case spoc_type_inp:
989  case spoc_type_poc:
990  if (out->level<=spoc_type_poc)
991  pips_assert("same side if early", in->side==out->side);
992  if (out->level<=spoc_type_alu)
993  sb_cat(code, " // nope\n");
994  // ELSE thr or mes...
995  else
996  {
997  generate_wiring_stage(code, in->stage, in->side, out->side, wiring);
998  if (in->level == spoc_type_inp)
999  {
1000  // the poc was passed by wiring...
1001  in->level = spoc_type_poc;
1002  set_component(wiring, in->stage, in->level, in->side);
1003  }
1004  }
1005  break;
1006  case spoc_type_alu:
1007  // out->level is after thr, so there is a side
1008  if (out->side!=-1)
1009  generate_wiring_stage(code, in->stage, -1, out->side, wiring);
1010  // else: X alu -> W alu, possibly because it operation is a copy
1011  break;
1012  case spoc_type_thr:
1013  case spoc_type_mes:
1014  case spoc_type_out:
1015  // no choice
1016  pips_assert("same side", in->side==out->side);
1017  sb_cat(code, " // nope\n");
1018  break;
1019  case spoc_type_nop:
1020  default:
1021  pips_internal_error("shoud not get there");
1022  }
1023 
1024  // record operation flipping
1025  if (out->level == spoc_type_alu &&
1026  dagvtx_optype(out->producer)==spoc_type_alu) // skip copy
1027  {
1028  vtxcontent cout = dagvtx_content(out->producer);
1029  list lins = vtxcontent_inputs(cout);
1030  pips_assert("sanity", in->side>=0 && lins);
1031  switch (gen_length(lins))
1032  {
1033  case 2:
1034  if (in->side==0)
1035  out->flip = !(in->image == ENTITY(CAR(lins)));
1036  else // in->side==1
1037  out->flip = (in->image == ENTITY(CAR(lins)));
1038  break;
1039  case 1:
1040  out->flip = (in->side==1);
1041  break;
1042  default:
1043  case 0:
1044  pips_internal_error("should not get there");
1045  }
1046  }
1047  }
1048  else // in->stage < out->stage
1049  {
1050  // let us do it with a recursion...
1051  int prefered;
1052  op_schedule saved = *in;
1053  switch (in->level)
1054  {
1055  case spoc_type_inp:
1056  case spoc_type_poc:
1057  set_component(wiring, in->stage, spoc_type_poc, in->side);
1058  _FALLTHROUGH_;
1059  case spoc_type_alu:
1060  // chose prefered side
1061  if (in->level==spoc_type_alu)
1062  // try direct, or default to 0
1063  prefered = (out->side>=0)? out->side: 0;
1064  else // take the right side as soon as possible?
1065  // ??? what if the path is not possible later?
1066  prefered = (out->side==-1)? in->side: out->side;
1067 
1068  // try both cases
1069  if (check_wiring_output(wiring, in->stage, prefered))
1070  {
1071  generate_wiring_stage(code, in->stage, in->side, prefered, wiring);
1072  set_component(wiring, in->stage, spoc_type_mes, prefered);
1073  in->stage++;
1074  in->side = prefered;
1075  in->level = spoc_type_inp;
1076  generate_wiring(code, in, out, wiring);
1077  }
1078  else if (check_wiring_output(wiring, in->stage, 1 - prefered))
1079  {
1080  generate_wiring_stage(code, in->stage, in->side, 1 - prefered, wiring);
1081  set_component(wiring, in->stage, spoc_type_mes, 1 - prefered);
1082  in->stage++;
1083  in->side = 1 - prefered;
1084  in->level = spoc_type_inp;
1085  generate_wiring(code, in, out, wiring);
1086  }
1087  else
1088  pips_internal_error("no available path...");
1089 
1090  // we may still use the result for something else... others?
1091  if (saved.level<=spoc_type_alu && out->level<=spoc_type_poc &&
1092  // restore to the previous stage
1093  saved.stage==out->stage-1)
1094  {
1095  pips_debug(7, "restoring previous schedule...\n");
1096  *in = saved;
1097  }
1098  if (in->level == spoc_type_inp)
1099  in->level = spoc_type_poc; // the poc was passed by wiring
1100  break;
1101  case spoc_type_thr:
1102  case spoc_type_mes:
1103  case spoc_type_out:
1104  // no choice, skip to input of next stage
1105  in->stage++;
1106  in->level = spoc_type_inp;
1107  generate_wiring(code, in, out, wiring);
1108  break;
1109  case spoc_type_nop:
1110  default:
1111  pips_internal_error("shoud not get there");
1112  }
1113  }
1114 }
1115 
1116 /* build up final pipeline code from various pieces
1117  * @param module
1118  * @param function_name to be generated
1119  * @param code output
1120  * @param head input, function parameters
1121  * @param body input, pipeline stage initialization
1122  * @param tail input, getting back reduction results
1123  * @param n_im_* number of in and out paramters to function
1124  * @param some_reductions if there are
1125  * @param p_* variables sent and received from pipeline
1126  */
1128 (string module,
1129  string function_name,
1130  // buffers which hold different parts of the code
1132  const string_buffer head,
1133  const string_buffer body,
1134  const string_buffer tail,
1135  // number of images in & out
1136  int n_im_out, int n_im_in,
1137  // parts which may be needed
1138  bool some_reductions, bool some_kernels,
1139  // input/output parameters
1140  const string out0, const string out1, const string in0, const string in1)
1141 {
1142  // function header: freia_error helper_function(freia_data_2d ...
1143  sb_cat(code,
1144  "\n"
1145  "// FREIA-SPoC helper function for module ", module, "\n"
1146  "freia_status ", function_name, "(\n");
1147  // first, image arguments
1148  if (n_im_out>0) sb_cat(code, " " FREIA_IMAGE "o0");
1149  if (n_im_out>1) sb_cat(code, ",\n " FREIA_IMAGE "o1");
1150  if (n_im_out!=0 && n_im_in>0) sb_cat(code, ",\n");
1151  if (n_im_in>0) sb_cat(code, " const " FREIA_IMAGE "i0");
1152  if (n_im_in>1) sb_cat(code, ",\n const " FREIA_IMAGE "i1");
1153 
1155 
1156  // end of headers (some arguments may have been added by stages),
1157  // and begin the function body
1158  sb_cat(code, ")\n{\n" FREIA_SPOC_DECL);
1159  if (some_reductions)
1160  sb_cat(code,
1161  " spoc_reduction reduc;\n"
1162  " freia_reduction_results redres;\n");
1163  if (some_kernels) sb_cat(code, " int i;\n");
1164  sb_cat(code, "\n");
1165 
1166  sb_cat(code,
1167  " // init pipe to nop\n"
1168  " spoc_init_pipe(&si, &sp, ", i2a(FREIA_DEFAULT_BPP), ");\n"
1169  "\n");
1170 
1172 
1173  // generate actual call to the accelerator
1175  if (some_reductions)
1178  " // actual call of spoc hardware\n"
1179  " freia_cg_template_process_2i_2o",
1180  "(&param, ", out0, ", ", out1, ", ", in0, ", ", in1, ");\n",
1181  NULL);
1182 
1183  if (some_reductions)
1184  sb_cat(code,
1185  "\n"
1186  " // get reductions\n"
1187  " freia_cg_read_reduction_results(&redres);\n");
1188 
1190 
1191  sb_cat(code, "\n return ret;\n}\n");
1192 }
1193 
1194 /* tell whether the image produced by prod is definitely consummed by v
1195  * given the global dag d and the set of vertex still to be computed todo.
1196  */
1197 static bool is_consummed_by_vertex(dagvtx prod, dagvtx v, dag d, set todo)
1198 {
1199  bool consummed;
1200  // no producer, no problem
1201  if (!prod)
1202  consummed = true;
1203  // the image is a global output, it must be kept
1204  else if (gen_in_list_p(prod, dag_outputs(d)))
1205  consummed = false;
1206  // the image is consummed by v
1207  else if (gen_in_list_p(v, dagvtx_succs(prod)))
1208  {
1209  set succs = set_make(set_pointer);
1210  set_assign_list(succs, dagvtx_succs(prod));
1211  set_del_element(succs, succs, v);
1212  // other todos expect this image?
1213  consummed = !set_intersection_p(succs, todo);
1214  set_free(succs);
1215  }
1216  else
1217  consummed = false;
1218  pips_debug(7, "%"_intFMT" is %sconsummed by %"_intFMT"\n",
1219  dagvtx_number(prod), consummed? "": "not ", dagvtx_number(v));
1220  return consummed;
1221 }
1222 
1223 /* generate a SPoC pipeline from a single DAG for module.
1224  *
1225  * @param module current
1226  * @param helper name of function to generate
1227  * @param code output here
1228  * @param dpipe dag to consider
1229  * @param lparams parameters to call helper
1230  * @return number of output images
1231  *
1232  * some side effects:
1233  * - if there is an overflow, dpipe updated with remaining vertices.
1234  * - accelerated statements are cleaned
1235  *
1236  * I should have really done an allocation on a infinite pipeline,
1237  * and then cut it, instead of this half measure to handle overflows,
1238  * but that would change a lot of things to go back.
1239  */
1241 (string module, string helper, string_buffer code, dag dpipe, list * lparams,
1242  const set output_images)
1243 {
1244  hash_table wiring = hash_table_make(hash_int, 128);
1245  list outs = NIL;
1246  bool some_reductions = false, some_kernels = false;
1247  int pipeline_depth = get_int_property(spoc_depth_prop);
1248 
1249  pips_debug(3, "running on '%s' for %d operations\n",
1250  module, (int) (gen_length(dag_vertices(dpipe)) -
1251  gen_length(dag_inputs(dpipe))));
1252  pips_assert("non empty dag", gen_length(dag_vertices(dpipe))>0);
1253 
1254  // build list of output entities from the pipe
1255  FOREACH(dagvtx, v, dag_outputs(dpipe))
1256  outs = CONS(entity, vtxcontent_out(dagvtx_content(v)), outs);
1257  outs = gen_nreverse(outs);
1258 
1259  // generate a helper function in some file
1260  int cst = 0;
1262  head = string_buffer_make(true),
1263  body = string_buffer_make(true),
1264  tail = string_buffer_make(true);
1265 
1266  // first arguments are out & in images
1267  int n_im_in = gen_length(dag_inputs(dpipe));
1268  pips_assert("0, 1, 2 input images", n_im_in>=0 && n_im_in<=2);
1269 
1270  // piped images in helper
1271  string p_in0 = "NULL", p_in1 = "NULL", p_out0 = "NULL", p_out1 = "NULL";
1272  // piped images in function
1273  entity a_in0 = NULL, a_in1 = NULL;
1274  dagvtx v_in0 = NULL;
1275 
1276  op_schedule in0, in1, out;
1277  list /* of entity */ limg = NIL;
1278 
1279  int live_images = 0;
1280 
1281  // build input arguments/parameters/arguments
1282  if (n_im_in>=1)
1283  {
1284  v_in0 = DAGVTX(CAR(dag_inputs(dpipe)));
1285  a_in0 = vtxcontent_out(dagvtx_content(v_in0));
1286  p_in0 = "i0";
1287  init_op_schedule(&in0, v_in0, 0);
1288  limg = CONS(entity, a_in0, NIL);
1289  live_images++;
1290  }
1291  else
1292  init_op_schedule(&in0, NULL, 0);
1293 
1294  if (n_im_in==1 && gen_length(dagvtx_succs(v_in0))>1)
1295  {
1296  // help scheduling by providing the first input twice.
1297  init_op_schedule(&in1, v_in0, 1);
1298  p_in1 = "i0";
1299  live_images++;
1300  }
1301  else if (n_im_in>=2)
1302  {
1303  dagvtx v_in1 = DAGVTX(CAR(CDR(dag_inputs(dpipe))));
1304  a_in1 = vtxcontent_out(dagvtx_content(v_in1));
1305  p_in1 = "i1";
1306  init_op_schedule(&in1, v_in1, 1);
1307  limg = gen_nconc(limg, CONS(entity, a_in1, NIL));
1308  live_images++;
1309  }
1310  else
1311  init_op_schedule(&in1, NULL, 1);
1312 
1313  list vertices = gen_nreverse(gen_copy_seq(dag_vertices(dpipe)));
1314  set todo = set_make(set_pointer);
1315  FOREACH(dagvtx, vi, dag_inputs(dpipe))
1316  gen_remove(&vertices, vi);
1317  set_assign_list(todo, vertices);
1318 
1319  set skipped = set_make(set_pointer);
1320 
1321  // expression/variable -> parameter string name
1322  hash_table hparams = hash_table_make(hash_pointer, 0);
1323 
1324  // keep track of current stage for comments, and to detect overflows
1325  int stage = -1;
1326 
1327  FOREACH(dagvtx, v, vertices)
1328  {
1329  pips_debug(3, "considering vertex %"_intFMT"\n", dagvtx_number(v));
1330 
1331  // skip inputs
1332  if (dagvtx_number(v)==0) break;
1333 
1334  // on overflow...
1335  if (!set_empty_p(skipped))
1336  {
1337  // check for dependencies on skipped vertices...
1338  bool toskip = false;
1339  SET_FOREACH(dagvtx, sk, skipped)
1340  {
1341  // skip because of missing deps
1342  if (gen_in_list_p(v, dagvtx_succs(sk))) {
1343  pips_debug(7, "skipping %"_intFMT", deps on %"_intFMT"\n",
1344  dagvtx_number(v), dagvtx_number(sk));
1345  toskip = true;
1346  break;
1347  }
1348  }
1349  // or no available output path, none created by consumming an image
1350  if (!toskip && dagvtx_succs(v) && live_images==2 &&
1351  !(is_consummed_by_vertex(in0.producer, v, dpipe, todo) ||
1352  is_consummed_by_vertex(in1.producer, v, dpipe, todo)))
1353  {
1354  pips_debug(7, "skipping %"_intFMT", no path\n", dagvtx_number(v));
1355  toskip = true;
1356  }
1357  if (toskip) {
1358  set_add_element(skipped, skipped, v);
1359  continue;
1360  }
1361  }
1362 
1363  pips_debug(7, "dealing with vertex %" _intFMT ", %d to go, %d path\n",
1364  dagvtx_number(v), set_size(todo), live_images);
1365 
1366  vtxcontent vc = dagvtx_content(v);
1367  pips_assert("there is a statement",
1371  // extract the api information now, because of scheduling side
1372  // effects on out so that out.provider may be changed on measures
1373  int optype = dagvtx_optype(v), opid = dagvtx_opid(v);
1374  const freia_api_t * api = get_freia_api(opid);
1375  pips_assert("AIPO function found", api!=NULL);
1376 
1377  set_del_element(todo, todo, v);
1378 
1379  // schedule...
1380  where_to_perform_operation(v, &in0, &in1, dpipe, todo, &out, wiring);
1381 
1382  // detect pipeline overflow
1383  if (out.stage >= pipeline_depth)
1384  {
1385  // pipeline is full, vi was not computed:
1386  pips_debug(3, "pipeline overflow on %" _intFMT "\n", dagvtx_number(v));
1387  set_add_element(todo, todo, v);
1388 
1389  // now, there may be other vertices which are computable...
1390  // but the splitting put there after this one in the vertex list
1391  // hmmm...
1392  set_add_element(skipped, skipped, v);
1393  }
1394  else // the vertex is added to the pipeline...
1395  {
1396  // record
1397  set_component(wiring, out.stage, out.level, out.side);
1398 
1399  // get needed parameters if any
1401  freia_extract_params(opid, call_arguments(c), head, NULL,
1402  hparams, &cst));
1403 
1404  some_reductions |= vtxcontent_optype(vc)==spoc_type_mes;
1405  some_kernels |= vtxcontent_optype(vc)==spoc_type_poc;
1406 
1407  // there may be regressions if it is a little bit out of order...
1408  // add a comment each time a new stage is started.
1409  if (out.stage!=stage)
1410  {
1411  stage = out.stage;
1412  sb_cat(body, "\n // STAGE ", i2a(stage), "\n");
1413  }
1414 
1415  // generate wiring, which may change flip stage on ALU operation
1416  // special case if in0==in1 is needed? no, rely on just_used
1417  if (in0.just_used)
1418  generate_wiring(body, &in0, &out, wiring);
1419 
1420  if (in1.just_used)
1421  generate_wiring(body, &in1, &out, wiring);
1422 
1423  // generate stage code
1424  basic_spoc_conf(optype, body, tail, out.stage, out.side, out.flip,
1425  &(api->spoc), v, hparams);
1426 
1427  bool
1428  in0_needed = image_is_needed(in0.producer, dpipe, todo),
1429  in1_needed = image_is_needed(in1.producer, dpipe, todo);
1430 
1431  // first, keep where it is...
1432  if (in0.stage==out.stage && in0.level==out.level && in0.side==out.side)
1433  in0 = out;
1434  else if (in1.stage==out.stage &&
1435  in1.level==out.level && in1.side==out.side)
1436  in1 = out;
1437  // else overwrite not needed used image
1438  else if (!in0_needed && in0.used)
1439  in0 = out;
1440  else if (!in1_needed && in1.used)
1441  in1 = out;
1442  // else, overwrite same image if not needed
1443  else if (!in0_needed || out.image==in0.image)
1444  {
1445  if (in1.image)
1446  in0 = out;
1447  else
1448  in1 = out; // rather keep it the available slot?
1449  }
1450  else if (!in1_needed || out.image==in1.image)
1451  {
1452  if (in0.image)
1453  in1 = out;
1454  else
1455  in0 = out; // idem
1456  }
1457  // the image is available twice which is needed
1458  else if (in0.image && in0.image == in1.image)
1459  {
1460  // we have the same image, overwrite the used one
1461  if (in0.used)
1462  in0 = out;
1463  else if (in1.used)
1464  in1 = out;
1465  // if none where used, overwrite the one on the current side
1466  // ??? in0.side == -1 && in1.side==-1 ?
1467  else if (in0.side == out.side)
1468  in0 = out;
1469  else if (in1.side == out.side)
1470  in1 = out;
1471  else if (out.side==-1)
1472  // just choose one?
1473  in0 = out;
1474  else
1475  pips_internal_error("should not get there (same image)?");
1476  }
1477  else
1478  {
1479  pips_assert("overflow mode", !set_empty_p(skipped));
1480  // ??? hmmm, we get there on overflow, if an input image is
1481  // still to be used, but 2 computed images are extracted.
1482  // what we are in effect doing is to modify the schedule,
1483  // possibly breaking the 2 live image property in the process,
1484  // in order to attempt to fill in the pipe a little more...
1485  if (out.image)
1486  {
1487  if (in0.just_used)
1488  {
1489  in0 = out;
1490  in0_needed = true;
1491  }
1492  else if (in1.just_used)
1493  {
1494  in1 = out;
1495  in1_needed = true;
1496  }
1497  else
1498  // not sure of the conditions above to choose between in0 and in1
1499  pips_internal_error("computed image not extracted...");
1500  }
1501  }
1502 
1503  // anyway, we must clean unuseful variables, because
1504  // the scheduling on image entities to check deps (still ?)
1505  if (!in0_needed && in0.producer!=out.producer)
1506  init_op_schedule(&in0, NULL, 0);
1507  if (!in1_needed && in1.producer!=out.producer)
1508  init_op_schedule(&in1, NULL, 0);
1509 
1510  // update count of live images for overflow mode
1511  live_images = 0;
1512  if (image_is_needed(in0.producer, dpipe, todo)) live_images++;
1513  if (image_is_needed(in1.producer, dpipe, todo)) live_images++;
1514  }
1515  }
1516 
1517  set computed = set_make(set_pointer);
1518  set_assign_list(computed, vertices);
1519  set_difference(computed, computed, todo);
1520 
1521  // pipeline interruption?
1522  if (!set_empty_p(todo))
1523  {
1524  // what are the effective outputs in the middle of the pipeline
1525  list new_outs = NIL;
1526  if (image_is_needed(in1.producer, dpipe, todo) &&
1527  !gen_in_list_p(in1.producer, dag_inputs(dpipe)))
1528  new_outs = CONS(entity, in1.image, new_outs);
1529  if (image_is_needed(in0.producer, dpipe, todo) &&
1530  !gen_in_list_p(in0.producer, dag_inputs(dpipe)))
1531  // should also check that in0!=in1?
1532  new_outs = CONS(entity, in0.image, new_outs);
1533 
1534  // gen_free_list(dag_outputs(dpipe));
1535  // dag_outputs(dpipe) = outs;
1536  gen_free_list(outs), outs = new_outs;
1537  }
1538 
1539  // cleanup dpipe of computed vertices
1540  FOREACH(dagvtx, vr, vertices)
1541  {
1542  if (set_belong_p(computed, vr))
1543  {
1544  dag_remove_vertex(dpipe, vr);
1548  free_dagvtx(vr);
1549  }
1550  }
1551 
1552  // hmmm???
1553  dag_compute_outputs(dpipe, NULL, output_images, NIL, false);
1554 
1555  gen_free_list(vertices), vertices = NIL;
1556  set_free(computed), computed = NULL;
1557 
1558  // handle pipe outputs (may have been interrupted)
1559  int n_im_out = gen_length(outs);
1560  pips_assert("0, 1, 2 output images", n_im_out>=0 && n_im_out<=2);
1561  pips_assert("some input or output images", n_im_out || n_im_in);
1562  if (n_im_out==0)
1563  {
1564  sb_cat(body, "\n // no output image\n");
1565  }
1566  else if (n_im_out==1)
1567  {
1568  entity imout = ENTITY(CAR(outs));
1569 
1570  // put producer in in0
1571  if (in1.image==in0.image)
1572  {
1573  pips_assert("image found", in0.image==imout);
1574  // choose the latest
1575  if (in1.stage>in0.stage || (in1.stage==in0.stage && in1.level>in0.level))
1576  out = in0, in0 = in1, in1 = out;
1577  }
1578  // else just take the right one
1579  else if (in1.image==imout && in0.image!=imout)
1580  out = in0, in0 = in1, in1 = out;
1581  else if (in0.image==imout)
1582  ; // ok
1583  else
1584  pips_internal_error("result image is not alive");
1585 
1586  out.image = imout;
1587  out.producer = NULL;
1588  out.level = spoc_type_out;
1589  out.stage = in0.stage;
1590  out.side = in0.side>=0? in0.side: 0; // choose 0 by default if alu
1591 
1592  // switch if side is not available
1593  if (in0.side<0 && !check_wiring_output(wiring, out.stage, out.side))
1594  out.side = 1 - out.side;
1595 
1596  sb_cat(body, "\n"
1597  " // output image ", entity_local_name(imout),
1598  " on ", i2a(out.side), "\n");
1599  generate_wiring(body, &in0, &out, wiring);
1600 
1601  // do not trust the default initialisation of the paths
1602  in0 = out;
1603  out.stage = pipeline_depth-1;
1604  sb_cat(body, "\n // fill in to the end...\n");
1605  generate_wiring(body, &in0, &out, wiring);
1606 
1607  if (out.side)
1608  p_out1 = "o0";
1609  else
1610  p_out0 = "o0";
1611 
1612  limg = CONS(entity, imout, limg);
1613  }
1614  else if (n_im_out==2)
1615  {
1616  entity
1617  out0 = ENTITY(CAR(outs)),
1618  out1 = ENTITY(CAR(CDR(outs)));
1619  int out0_side, out1_side;
1620 
1621  pips_assert("output two results in two variables", out0!=out1);
1622 
1623  // make out0 match in0 and out1 match in1
1624  if (out0 != in0.image)
1625  out = in0, in0 = in1, in1 = out;
1626  pips_assert("results are available", out0==in0.image && out1==in1.image);
1627 
1628  pips_debug(7, "out0 %s out1 %s in0(%d.%d.%d) %s in1(%d.%d.%d) %s\n",
1629  entity_local_name(out0), entity_local_name(out1),
1630  in0.stage, in0.level, in0.side, entity_local_name(in0.image),
1631  in1.stage, in1.level, in1.side, entity_local_name(in1.image));
1632 
1633  // the more advanced image in the pipe decides its output side
1634  bool in0_advanced = in0.stage>in1.stage ||
1635  (in0.stage==in1.stage && in0.level>in1.level);
1636 
1637  if (in0_advanced)
1638  {
1639  out0_side = in0.side;
1640  if (out0_side==-1) out0_side = 0; // alu, choose!
1641  out1_side = 1 - out0_side;
1642  }
1643  else // in1 is more forward
1644  {
1645  out1_side = in1.side;
1646  if (out1_side==-1) out1_side = 1; // alu, choose!
1647  out0_side = 1 - out1_side;
1648  }
1649 
1650  pips_assert("2 images: one output on each side",
1651  (out0_side==0 && out1_side==1) || (out0_side==1 && out1_side==0));
1652 
1653  limg = CONS(entity, out0, CONS(entity, out1, limg));
1654  if (out1_side) // out1 on side 1, thus out0 side 0
1655  p_out0 = "o0", p_out1 = "o1";
1656  else // they are reversed
1657  p_out0 = "o1", p_out1 = "o0";
1658 
1659  int out_stage = (in0.stage>in1.stage)? in0.stage: in1.stage;
1660 
1661  sb_cat(body, "\n"
1662  " // output image ", entity_local_name(out0),
1663  " on ", i2a(out0_side));
1664  sb_cat(body, " and image ", entity_local_name(out1),
1665  " on ", i2a(out1_side), "\n");
1666 
1667  // extract the first one.
1668  out.image = out0;
1669  out.producer = NULL;
1670  out.level = spoc_type_out;
1671  out.side = out0_side;
1672  out.stage = out_stage;
1673  generate_wiring(body, &in0, &out, wiring);
1674 
1675  // do not trust the default initialisation of the pipeline
1676  in0 = out;
1677  out.stage = pipeline_depth-1;
1678  sb_cat(body, "\n // fill in to the end...\n");
1679  generate_wiring(body, &in0, &out, wiring);
1680 
1681  // extract the seconde one
1682  sb_cat(body, "\n");
1683  out.image = out1;
1684  out.producer = NULL;
1685  out.level = spoc_type_out;
1686  out.side = out1_side;
1687  out.stage = out_stage;
1688  generate_wiring(body, &in1, &out, wiring);
1689 
1690  // do not trust the default initialisation of the pipeline
1691  in1 = out;
1692  out.stage = pipeline_depth-1;
1693  sb_cat(body, "\n // fill in to the end...\n");
1694  generate_wiring(body, &in1, &out, wiring);
1695  }
1696  else
1697  pips_internal_error("only 0 to 2 output images!");
1698 
1699  // handle function image arguments
1701 
1702  // build whole code from various pieces
1703  freia_spoc_code_buildup(module, helper, code, head, body, tail,
1704  n_im_out, n_im_in, some_reductions, some_kernels,
1705  p_out0, p_out1, p_in0, p_in1);
1706 
1707  // cleanup
1708  gen_free_list(outs);
1709  set_free(todo);
1710  set_free(skipped);
1711  hash_table_free(wiring);
1712  string_buffer_free(&head);
1713  string_buffer_free(&body);
1714  string_buffer_free(&tail);
1715 
1716  return n_im_out;
1717 }
1718 
1719 /***************************************************************** MISC UTIL */
1720 
1721 /* current list of computable that may be used to know about the
1722  * global context when comparing to vertices in "dagvtx_spoc_priority".
1723  */
1725 // idem for vertices computed in current pipe
1727 
1728 #if 0
1729 /* return the number of poc operations which have the same input node
1730  * as ref from the global list, including the ref itself.
1731  */
1732 static int poc_count_same_inputs(const dagvtx ref)
1733 {
1734  pips_assert("global list is defined", dagvtx_spoc_priority_computables);
1735  pips_assert("vertex is in list",
1737  pips_assert("vertex is a poc operation", dagvtx_optype(ref)==spoc_type_poc);
1738 
1740  int n = 0;
1741 
1743  if (dagvtx_optype(v)==spoc_type_poc &&
1745  n++;
1746 
1748  if (dagvtx_optype(v)==spoc_type_poc &&
1750  n++;
1751 
1752  pips_assert("at least myself", n>0);
1753  return n;
1754 }
1755 #endif
1756 
1757 /* ? = Morpho(I); ? = ALU(I, ?);
1758  */
1760 {
1761  return
1764  gen_length(vtxcontent_inputs(c2))==2 &&
1766 }
1767 
1768 /* comparison function for sorting dagvtx in qsort,
1769  * this is deep voodoo, because the priority has an impact on
1770  * correctness? that should not be the case as only computations
1771  * allowed by dependencies are schedule.
1772  * non implemented functions are pushed late.
1773  * tells v1 < v2 => -1 => v1 BEFORE v2
1774  */
1775 static int dagvtx_spoc_priority(const dagvtx * v1, const dagvtx * v2)
1776 {
1777  string why = "none";
1778  int result = 0;
1779  vtxcontent
1780  c1 = dagvtx_content(*v1),
1781  c2 = dagvtx_content(*v2);
1782 
1783  // prioritize first scalar ops, measures and last copies
1784  // if there is only one of them
1785  if (vtxcontent_optype(c1)!=vtxcontent_optype(c2))
1786  {
1787  // non implemented operations
1789  result = 1, why = "not";
1790  else if (vtxcontent_optype(c2)==spoc_type_sni)
1791  result = -1, why = "not";
1792  // then scalars operations first to remove (scalar) dependences
1793  else if (vtxcontent_optype(c1)==spoc_type_oth)
1794  result = -1, why = "scal";
1795  else if (vtxcontent_optype(c2)==spoc_type_oth)
1796  result = 1, why = "scal";
1797  // then measurements are put first
1798  else if (vtxcontent_optype(c1)==spoc_type_mes)
1799  result = -1, why = "mes";
1800  else if (vtxcontent_optype(c2)==spoc_type_mes)
1801  result = 1, why = "mes";
1802  // the copies are performed last...
1803  else if (vtxcontent_optype(c1)==spoc_type_nop)
1804  result = 1, why = "copy";
1805  else if (vtxcontent_optype(c2)==spoc_type_nop)
1806  result = -1, why = "copy";
1807  // special morpho/alu case with a shared input image
1808  else if (erode_alu_shared_p(c1, c2))
1809  result = 1, why = "shared";
1810  else if (erode_alu_shared_p(c2, c1))
1811  result = -1, why = "shared";
1812  }
1813 
1814  if (result==0)
1815  {
1816  // if not set by previous case, use other criterions
1817  int
1818  l1 = (int) gen_length(vtxcontent_inputs(c1)),
1819  l2 = (int) gen_length(vtxcontent_inputs(c2));
1820 
1821  // count non mesure successors:
1822  int nms1 = 0, nms2 = 0;
1823 
1824  FOREACH(dagvtx, vs1, dagvtx_succs(*v1))
1825  if (dagvtx_optype(vs1)!=spoc_type_mes) nms1++;
1826 
1827  FOREACH(dagvtx, vs2, dagvtx_succs(*v2))
1828  if (dagvtx_optype(vs2)!=spoc_type_mes) nms2++;
1829 
1830  // the decision process is mostly based on the number of inputs
1831  // images to the two compared operations.
1832  if (l1!=l2 && (l1==0 || l2==0))
1833  // put image generators at the end, after any other computation
1834  result = l2-l1, why = "args";
1835  else if (nms1!=nms2 && l1==1 && l2==1)
1836  // the less successors the better? the rational is:
1837  // - mesures are handled before and do not have successors anyway,
1838  // - so this is about whether a result of an unary op is reused by
1839  // two nodes, in which case it will just jam the pipeline, so
1840  // try to put other computations before it. Note that mes
1841  // successors do not really count, as the image is not lost.
1842  result = nms1 - nms2, why = "succs";
1843  else if (l1!=l2)
1844  // else ??? no effect on my validation.
1845  result = l2-l1, why = "args2";
1846  else if (vtxcontent_optype(c1)!=vtxcontent_optype(c2))
1847  // otherwise use the op types, which are somehow ordered
1848  // so that if all is well the pipe is filled in order.
1849  result = vtxcontent_optype(c1) - vtxcontent_optype(c2), why = "ops";
1850  else
1851  /*
1852  // unsuccessful attempt for freia_43
1853  if (vtxcontent_optype(c1)==spoc_type_poc)
1854  {
1855  int
1856  same1 = poc_count_same_inputs(*v1),
1857  same2 = poc_count_same_inputs(*v2);
1858  if (same1!=same2)
1859  // chose the one with more inputs
1860  result = same1-same2, why = "pocinputs";
1861  else
1862  // same as last case
1863  result = dagvtx_number(*v1) - dagvtx_number(*v2), why = "stats";
1864  }
1865  else */
1866  // if all else fails, rely on statement numbers.
1867  result = dagvtx_number(*v1) - dagvtx_number(*v2), why = "stats";
1868  }
1869 
1870  pips_debug(7, "%" _intFMT " %s %s %" _intFMT " %s (%s)\n",
1871  dagvtx_number(*v1), dagvtx_operation(*v1),
1872  result<0? ">": (result==0? "=": "<"),
1873  dagvtx_number(*v2), dagvtx_operation(*v2), why);
1874 
1875  pips_assert("total order", v1==v2 || result!=0);
1876  return result;
1877 }
1878 
1879 /************************************************************ IMPLEMENTATION */
1880 
1881 /* update sure/maybe set of live images after computing vertex v
1882  * that is the images that may be output from the pipeline.
1883  * this is voodoo...
1884  */
1885 static void live_update(dag d, dagvtx v, set sure, set maybe)
1886 {
1887  vtxcontent c = dagvtx_content(v);
1888 
1889  // skip "other" statements
1890  if (dagvtx_other_stuff_p(v))
1891  return;
1892 
1893  list ins = vtxcontent_inputs(c);
1894  int nins = gen_length(ins);
1895  entity out = vtxcontent_out(c);
1896  int nout = out!=entity_undefined? 1: 0;
1897  list preds = dag_vertex_preds(d, v);
1898 
1899  set all = set_make(set_pointer);
1900  set_union(all, sure, maybe);
1901  pips_assert("inputs are available", list_in_set_p(preds, all));
1902  set_free(all), all = NULL;
1903 
1904  switch (nins)
1905  {
1906  case 0:
1907  // no input image is used
1908  // maybe is unchanged
1909  // I guess it is not "NOP"...
1910  pips_assert("one output...", nout==1);
1911  set_union(maybe, maybe, sure);
1912  break;
1913  case 1:
1914  if (nout)
1915  {
1916  // 1 -> 1
1917  if (set_size(sure)==1 && !list_in_set_p(preds, sure))
1918  {
1919  set_assign_list(maybe, preds);
1920  set_union(maybe, maybe, sure);
1921  }
1922  else
1923  {
1924  set_append_list(maybe, preds);
1925  }
1926  }
1927  break;
1928  case 2:
1929  // any of the inputs may be kept
1930  set_assign_list(maybe, preds);
1931  break;
1932  default:
1933  pips_internal_error("unpexted number of inputs to vertex: %d", nins);
1934  }
1935 
1936  if (nout==1)
1937  {
1938  set_clear(sure);
1939  set_add_element(sure, sure, v);
1940  }
1941  // else sure is kept
1942  set_difference(maybe, maybe, sure);
1943 
1944  // cleanup
1945  gen_free_list(preds), preds = NIL;
1946 }
1947 
1948 /* returns an allocated set of vertices with live outputs.
1949  */
1950 static set output_arcs(dag d, set vs)
1951 {
1952  set out_nodes = set_make(set_pointer);
1953  // direct output nodes
1954  SET_FOREACH(dagvtx, v, vs)
1955  {
1956  if (vtxcontent_out(dagvtx_content(v))!=entity_undefined)
1957  {
1958  // this vertex produces an image
1959  bool is_needed = false;
1960 
1961  // it is needed if...
1962  list succs = dagvtx_succs(v);
1963  if (gen_in_list_p(v, dag_outputs(d)))
1964  is_needed = true;
1965  else if (succs)
1966  {
1967  // some succs are not yet computed...
1968  FOREACH(dagvtx, vsucc, succs)
1969  if (!set_belong_p(vs, vsucc))
1970  is_needed = true;
1971  }
1972  // else there is no successor!?
1973 
1974  if (is_needed)
1975  set_add_element(out_nodes, out_nodes, v);
1976  }
1977  }
1978  return out_nodes;
1979 }
1980 
1981 /* how many output arcs from this set of vertices?
1982  */
1983 static int number_of_output_arcs(dag d, set vs)
1984 {
1985  set out_nodes = output_arcs(d, vs);
1986  int n_arcs = set_size(out_nodes);
1987  set_free(out_nodes);
1988  return n_arcs;
1989 }
1990 
1991 /* @return whether it is a 3x3 convolution
1992  */
1993 static bool convolution_33(dagvtx v)
1994 {
1995  if (freia_convolution_p(v)) {
1996  _int w, h;
1997  if (freia_convolution_width_height(v, &w, &h, false) && w==3 && h==3)
1998  return true;
1999  }
2000  return false;
2001 }
2002 
2003 /* does this dag contains a spoc non implemented operation?
2004  */
2005 static bool dag_spoc_not_implemented(dag d)
2006 {
2007  FOREACH(dagvtx, v, dag_vertices(d))
2008  if (dagvtx_optype(v)==spoc_type_sni ||
2009  // special handling of convolution
2010  (freia_convolution_p(v) && !convolution_33(v)))
2011  return true;
2012  return false;
2013 }
2014 
2015 /* return first vertex in the list which is compatible, or NULL if none.
2016  */
2017 static dagvtx first_which_may_be_added
2018  (dag dall,
2019  set current, // of dagvtx
2020  list lv, // of candidate dagvtx
2021  set sure, // of dagvtx
2022  set maybe) // image entities
2023 {
2024  dagvtx chosen = NULL;
2025  set inputs = set_make(set_pointer);
2026  set current_output = output_arcs(dall, current);
2027  int n_outputs = set_size(current_output);
2028  pips_assert("should be okay at first!", n_outputs<=2);
2029 
2030  pips_debug(8, "#outputs = %d\n", n_outputs);
2031 
2032  // output arcs from this subset
2033  // set outputs = output_arcs(current);
2034 
2035  FOREACH(dagvtx, v, lv)
2036  {
2037  pips_debug(8, "considering vertex %"_intFMT"\n", dagvtx_number(v));
2038  pips_assert("not yet there", !set_belong_p(current, v));
2039 
2040  // some intermediate stuff
2041  if (dagvtx_optype(v)==spoc_type_oth)
2042  {
2043  chosen = v;
2044  break;
2045  }
2046 
2047  // no image is produce, so no image output is added...
2048  if (!dagvtx_image(v))
2049  {
2050  pips_assert("is a mesure", dagvtx_optype(v)==spoc_type_mes);
2051  chosen = v;
2052  break;
2053  }
2054 
2055  list preds = dag_vertex_preds(dall, v);
2056  set_assign_list(inputs, preds);
2057  pips_debug(8, "#inputs = %d\n", set_size(inputs));
2058  int npreds = gen_length(preds);
2059  gen_free_list(preds), preds = NIL;
2060 
2061  //pips_debug(7, "vertex %"_intFMT": %d preds\n", dagvtx_number(v), npreds);
2062 
2063  if (npreds==2) // binary alu operations...
2064  {
2065  if (!set_inclusion_p(sure, inputs))
2066  continue;
2067  // two lives, but the var reuse will break the pipe by hidding
2068  // the other live which is not used by the computation of v.
2069  if (n_outputs==2 && set_size(inputs)==1)
2070  continue;
2071 
2072  // another more general case from freia_68
2073  set all_lives = set_make(set_pointer);
2074  set_intersection(all_lives, inputs, maybe);
2075  set_union(all_lives, current_output, all_lives);
2076  int n_lives = set_size(all_lives);
2077  set_free(all_lives);
2078 
2079  // cannot do, we would go over the limit...
2080  if (n_lives>2)
2081  continue;
2082  }
2083 
2084  set_add_element(current, current, v);
2085  int narcs_with_v = number_of_output_arcs(dall, current);
2086  set_del_element(current, current, v);
2087 
2088  if (narcs_with_v <= 2)
2089  {
2090  chosen = v;
2091  break;
2092  }
2093  }
2094  // none found
2095  set_free(inputs);
2096  return chosen;
2097 }
2098 
2099 /* split dag dall into a list of pipelinable dags
2100  * which must be processed in that order (?)
2101  * side effect: dall is more or less consummed...
2102  */
2103 static list /* of dags */ split_dag(dag initial, const set output_images)
2104 {
2105  // this may happen if an input image is also an output image...
2106  // pips_assert("no image reuse", single_image_assignement_p(initial));
2107  if (!single_image_assignement_p(initial))
2108  pips_user_warning("still some image reuse...\n");
2109 
2110  // ifdebug(1) pips_assert("initial dag ok", dag_consistent_p(initial));
2111  // if everything was removed by optimizations, there is nothing to do.
2112  if (dag_computation_count(initial)==0) return NIL;
2113 
2114  dag dall = copy_dag(initial);
2115  int nvertices = gen_length(dag_vertices(dall));
2116  list ld = NIL, lcurrent = NIL;
2117  set
2118  current = set_make(set_pointer),
2119  computed = set_make(set_pointer),
2120  maybe = set_make(set_pointer),
2121  sure = set_make(set_pointer),
2122  avails = set_make(set_pointer);
2123 
2124  // well, there are not all available always!
2125  set_assign_list(maybe, dag_inputs(dall));
2126  // set_assign(avails, maybe);
2127  set_assign(computed, maybe);
2128  int count = 0;
2129 
2130  do
2131  {
2132  count++;
2133  set_union(avails, sure, maybe);
2134 
2135  ifdebug(4) {
2136  pips_debug(4, "round %d:\n", count);
2137  set_fprint(stderr, "computed", computed,
2138  (gen_string_func_t) dagvtx_to_string);
2139  set_fprint(stderr, "current", current,
2140  (gen_string_func_t) dagvtx_to_string);
2141  set_fprint(stderr, "avails", avails,
2142  (gen_string_func_t) dagvtx_to_string);
2143  set_fprint(stderr, "maybe", maybe, (gen_string_func_t) dagvtx_to_string);
2144  set_fprint(stderr, "sure", sure, (gen_string_func_t) dagvtx_to_string);
2145  }
2146 
2147  list computables = dag_computable_vertices(dall, computed, avails, current);
2148  dagvtx_spoc_priority_computables = computables;
2149  dagvtx_spoc_priority_current = lcurrent;
2150  gen_sort_list(computables,
2151  (int(*)(const void*,const void*)) dagvtx_spoc_priority);
2152  dagvtx_spoc_priority_computables = NIL;
2153  dagvtx_spoc_priority_current = NIL;
2154 
2155  pips_assert("something must be computable if current is empty",
2156  computables || !set_empty_p(current));
2157 
2158  pips_debug(4, "%d computable vertices\n", (int) gen_length(computables));
2159  ifdebug(5) dagvtx_nb_dump(stderr, "computables", computables);
2160 
2161  // take the first one possible in the pipe, if any
2162  dagvtx vok =
2163  first_which_may_be_added(dall, current, computables, sure, maybe);
2164 
2165  if (vok && (dagvtx_optype(vok)==spoc_type_sni ||
2166  (freia_convolution_p(vok) && !convolution_33(vok)))
2167  && lcurrent)
2168  // extract non implemented nodes alone only!
2169  vok = NULL;
2170 
2171  if (vok)
2172  {
2173  pips_debug(5, "extracting %" _intFMT "...\n", dagvtx_number(vok));
2174  set_add_element(current, current, vok);
2175  lcurrent = CONS(dagvtx, vok, lcurrent);
2176  set_add_element(computed, computed, vok);
2177  live_update(dall, vok, sure, maybe);
2178  // set_union(avails, sure, maybe);
2179  }
2180 
2181  // no stuff vertex can be added, or it was the last one,
2182  // or it is not implemented and thus to be extracted "alone"
2183  if (!vok || set_size(computed)==nvertices ||
2184  (vok && (dagvtx_optype(vok)==spoc_type_sni ||
2185  (freia_convolution_p(vok) && !convolution_33(vok)))))
2186  {
2187  // ifdebug(5)
2188  // set_fprint(stderr, "closing current", current, )
2189  pips_debug(5, "closing current...\n");
2190  pips_assert("current not empty", !set_empty_p(current));
2191 
2192  // gen_sort_list(lcurrent, (gen_cmp_func_t) dagvtx_ordering);
2193  lcurrent = gen_nreverse(lcurrent);
2194  // close current and build a deterministic dag...
2195  dag nd = make_dag(NIL, NIL, NIL);
2196  FOREACH(dagvtx, v, lcurrent)
2197  {
2198  pips_debug(7, "extracting node %" _intFMT "\n", dagvtx_number(v));
2199  dag_append_vertex(nd, copy_dagvtx_norec(v));
2200  }
2201  dag_compute_outputs(nd, NULL, output_images, NIL, false);
2202  dag_cleanup_other_statements(nd);
2203 
2204  ifdebug(7) {
2205  // dag_dump(stderr, "updated dall", dall);
2206  dag_dump(stderr, "pushed dag", nd);
2207  }
2208 
2209  // update global list of dags to return.
2210  ld = CONS(dag, nd, ld);
2211 
2212  // cleanup
2213  gen_free_list(lcurrent), lcurrent = NIL;
2214  set_clear(current);
2215  set_clear(sure);
2216  set_assign(maybe, computed);
2217  }
2218 
2219  gen_free_list(computables);
2220  }
2221  while (set_size(computed)!=nvertices);
2222 
2223  // checks and cleanup
2224  pips_assert("current empty list", !lcurrent);
2225  pips_assert("all vertices were computed", set_size(computed)==nvertices);
2226  set_free(current);
2227  set_free(computed);
2228  set_free(sure);
2229  set_free(maybe);
2230  set_free(avails);
2231  free_dag(dall);
2232 
2233  pips_debug(5, "returning %d dags\n", (int) gen_length(ld));
2234  return gen_nreverse(ld);
2235 }
2236 
2237 /* generate helpers for statements in ls of module
2238  * output resulting functions in helper, which may be empty in some cases.
2239  * @param module
2240  * @param ls list of statements for the dag (in reverse order)
2241  * @param helper output file
2242  * @param helpers created functions
2243  * @param number current helper dag count
2244  * @return list of intermediate images to allocate
2245  */
2246 list freia_spoc_compile_calls
2247  (string module,
2248  dag fulld,
2249  sequence sq,
2250  list /* of statements */ ls,
2251  const hash_table occs,
2252  hash_table exchanges,
2253  const set output_images,
2254  FILE * helper_file,
2255  set helpers,
2256  int number)
2257 {
2258  // build DAG for ls
2259  pips_debug(3, "considering %d statements\n", (int) gen_length(ls));
2260  pips_assert("some statements", ls);
2261 
2262  int n_op_init, n_op_init_copies;
2263  freia_aipo_count(fulld, &n_op_init, &n_op_init_copies);
2264 
2265  // must have distinct images...
2266  hash_table init = hash_table_make(hash_pointer, 0);
2267  list new_images = dag_fix_image_reuse(fulld, init, occs);
2268 
2269  list added_before = NIL, added_after = NIL;
2270  freia_dag_optimize(fulld, exchanges, &added_before, &added_after);
2271 
2272  // remove copies and duplicates if possible...
2273  // ??? maybe there should be an underlying transitive closure? not sure.
2274  int n_op_opt, n_op_opt_copies;
2275  freia_aipo_count(fulld, &n_op_opt, &n_op_opt_copies);
2276 
2277  fprintf(helper_file,
2278  "\n"
2279  "// dag %d: %d ops and %d copies, "
2280  "optimized to %d ops and %d+%d+%d copies\n",
2281  number, n_op_init, n_op_init_copies,
2282  n_op_opt, n_op_opt_copies,
2283  (int) gen_length(added_before), (int) gen_length(added_after));
2284 
2285  // dump final dag
2286  dag_dot_dump_prefix(module, "dag_cleaned_", number, fulld,
2287  added_before, added_after);
2288 
2289  string fname_fulldag = strdup(cat(module, "_spoc", HELPER, i2a(number)));
2290 
2291  // split dag in one-pipe dags.
2292  list ld = split_dag(fulld, output_images);
2293 
2294  // nothing to do!
2295  // it would have been interesting not to create thehelper file in this case.
2296  // if (ld==NIL) return;
2297 
2298  FOREACH(dag, dfix, ld)
2299  freia_hack_fix_global_ins_outs(fulld, dfix);
2300 
2301  // globally remaining statements
2302  set global_remainings = set_make(set_pointer);
2303  set_assign_list(global_remainings, ls);
2304 
2306 
2307  int n_spoc_calls = 0;
2308  int n_pipes = 0;
2309  int stnb = -1;
2310 
2311  set stats = set_make(set_pointer), dones = set_make(set_pointer);
2312 
2313  FOREACH(dag, d, ld)
2314  {
2315  // skip non implemented stuff
2316  if (dag_spoc_not_implemented(d))
2317  continue;
2318 
2319  // fix connectivity
2320  dag_statements(stats, d);
2321  freia_migrate_statements(sq, stats, dones);
2322  set_union(dones, dones, stats);
2323 
2324  set remainings = set_make(set_pointer);
2326  // remove special inputs nodes
2327  // FOREACH(dagvtx, inp, dag_inputs(d))
2328  // set_del_element(remainings, remainings, inp);
2329 
2330  // generate a new helper function for dag d
2331  string fname_dag = strdup(cat(fname_fulldag, "_", i2a(n_pipes++)));
2332 
2333  ifdebug(4) dag_dump(stderr, "d", d);
2334  dag_dot_dump(module, fname_dag, d, NIL, NIL);
2335 
2336  // one logical pipeline may be split because of overflow
2337  // the dag is updated to reflect that as a code generation side effect
2338  int split = 0;
2339  while (dag_vertices(d))
2340  {
2341  // fix internal ins/outs, that are tempered with by split & overflows
2343 
2344  ifdebug(6) {
2345  pips_debug(4, "dag for split %d\n", split);
2346  dag_dump(stderr, "d", d);
2347  }
2348 
2349  string fname_split = strdup(cat(fname_dag, "_", i2a(split++)));
2350  list /* of expression */ lparams = NIL;
2351 
2352  _int nout = freia_spoc_pipeline(module, fname_split, code, d, &lparams,
2353  output_images);
2354  stnb = freia_substitute_by_helper_call(d, global_remainings, remainings,
2355  ls, fname_split, lparams, helpers, stnb);
2356  // record (simple) signature
2357  hash_put(init, local_name_to_top_level_entity(fname_split), (void*) nout);
2358  free(fname_split), fname_split = NULL;
2359  }
2360 
2361  n_spoc_calls += split;
2362  fprintf(helper_file, "// split %d: %d cut%s\n",
2363  n_pipes-1, split, split>1? "s": "");
2364 
2365  set_free(remainings), remainings = NULL;
2366  free(fname_dag), fname_dag = NULL;
2367  }
2368 
2369  set_free(stats);
2370  set_free(dones);
2371 
2372  fprintf(helper_file, "// # SPOC calls: %d\n", n_spoc_calls);
2373 
2374  freia_insert_added_stats(ls, added_before, true);
2375  added_before = NIL;
2376 
2377  freia_insert_added_stats(ls, added_after, false);
2378  added_after = NIL;
2379 
2380  string_buffer_to_file(code, helper_file);
2382 
2383  // cleanup
2384  set_free(global_remainings), global_remainings = NULL;
2385  free(fname_fulldag), fname_fulldag = NULL;
2386  FOREACH(dag, dc, ld)
2387  free_dag(dc);
2388  gen_free_list(ld);
2389 
2390  // deal with new images
2391  list real_new_images =
2392  freia_allocate_new_images_if_needed(ls, new_images, occs, init, init);
2393  gen_free_list(new_images);
2395  return real_new_images;
2396 }
float a2sf[2] __attribute__((aligned(16)))
USER generates a user error (i.e., non fatal) by printing the given MSG according to the FMT.
Definition: 3dnow.h:3
static void node(FILE *out, string name)
Build for module name a node and link to its successors.
Definition: graph.c:56
int get_int_property(const string)
void free_dag(dag p)
void free_dagvtx(dagvtx p)
static reference ref
Current stmt (an integer)
Definition: adg_read_paf.c:163
static FILE * out
Definition: alias_check.c:128
void const char const char const int
_int dagvtx_optype(const dagvtx v)
Definition: dag-utils.c:116
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
void freia_hack_fix_global_ins_outs(dag dfull, dag d)
catch some cases of missing outs between splits...
Definition: dag-utils.c:2166
entity dagvtx_image(const dagvtx v)
return the produced image or NULL
Definition: dag-utils.c:82
void dag_remove_vertex(dag d, const dagvtx v)
remove vertex v from dag d.
Definition: dag-utils.c:570
void dag_dump(FILE *out, const string what, const dag d)
for dag debug
Definition: dag-utils.c:212
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
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
string dagvtx_operation(const dagvtx v)
Definition: dag-utils.c:134
_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
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
void freia_add_image_arguments(list limg, list *lparams)
prepend limg images in front of the argument list limg is consummed by the operation.
Definition: freia-utils.c:1234
list freia_get_vertex_params(const dagvtx v)
Definition: freia-utils.c:578
list freia_extract_params(const int napi, list args, string_buffer head, string_buffer head2, hash_table params, int *nparams)
returns an allocated expression list of the parameters only (i.e.
Definition: freia-utils.c:613
void hwac_kill_statement(statement s)
remove contents of statement s.
Definition: freia-utils.c:761
list freia_allocate_new_images_if_needed(list ls, list images, const hash_table occs, const hash_table init, const hash_table signatures)
insert image allocation if needed, for intermediate image inserted before if an image is used only tw...
Definition: freia-utils.c:1650
void freia_migrate_statements(sequence sq, const set stats, const set before)
Definition: freia-utils.c:1905
int freia_substitute_by_helper_call(dag d, set global_remainings, set remainings, list ls, const string function_name, list lparams, set helpers, int preceeding)
substitute those statement in ls that are in dag d and accelerated by a call to function_name(lparams...
Definition: freia-utils.c:1073
const freia_api_t * get_freia_api(int index)
Definition: freia-utils.c:477
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
void freia_insert_added_stats(list ls, list stats, bool before)
insert statements to actual code sequence in "ls" BEWARE that ls is assumed to be in reverse order....
Definition: freia-utils.c:1185
#define cat(args...)
Definition: freia.h:41
#define HELPER
Definition: freia.h:38
#define FREIA_DEFAULT_BPP
Definition: freia.h:53
#define sb_cat(args...)
Definition: freia.h:42
#define FREIA_IMAGE
Definition: freia.h:52
#define T
Definition: freia_spoc.c:49
static int find_first_crossing(hash_table wiring, int stage, int level)
return the first stage after stage/level with both paths available
Definition: freia_spoc.c:531
static list dagvtx_spoc_priority_computables
current list of computable that may be used to know about the global context when comparing to vertic...
Definition: freia_spoc.c:1724
static bool check_wiring_output(hash_table wiring, int stage, int side)
can I get out of stage on this side?
Definition: freia_spoc.c:499
static bool available_component(hash_table wiring, int stage, int level, int side)
Definition: freia_spoc.c:523
static void basic_spoc_conf(spoc_hardware_type op, string_buffer body, string_buffer tail, int stage, int side, bool flip, const spoc_hw_t *conf, dagvtx orig, hash_table hp)
basic configuration generation for a stage, depending on hw description
Definition: freia_spoc.c:361
static void generate_wiring_stage(string_buffer code, int stage, int in_side, int out_side, hash_table wiring)
all possible wirings at one stage
Definition: freia_spoc.c:904
static void generate_wiring(string_buffer code, op_schedule *in, op_schedule *out, hash_table wiring)
generate wire code from in to out, record choices in wiring.
Definition: freia_spoc.c:949
static _int freia_spoc_pipeline(string module, string helper, string_buffer code, dag dpipe, list *lparams, const set output_images)
generate a SPoC pipeline from a single DAG for module.
Definition: freia_spoc.c:1241
static void print_op_schedule(FILE *out, const string name, const op_schedule *op)
Definition: freia_spoc.c:472
static bool image_is_needed(dagvtx prod, dag d, set todo)
is image needed?
Definition: freia_spoc.c:446
static void init_op_schedule(op_schedule *op, dagvtx v, int side)
Definition: freia_spoc.c:412
static _int component_index(int stage, int level, int side)
Definition: freia_spoc.c:504
#define F
Definition: freia_spoc.c:50
static bool erode_alu_shared_p(vtxcontent c1, vtxcontent c2)
? = Morpho(I); ? = ALU(I, ?);
Definition: freia_spoc.c:1759
static int spoc_measure_n_params(spoc_measure_t measure)
Definition: freia_spoc.c:278
static void set_component(hash_table wiring, int stage, int level, int side)
Definition: freia_spoc.c:511
static void spoc_alu_conf(spoc_alu_t alu, string_buffer body, __attribute__((__unused__)) string_buffer tail, int stage, bool flip, dagvtx orig, hash_table hp)
generate a configuration for the ALU hardware component.
Definition: freia_spoc.c:149
static bool is_consummed_by_vertex(dagvtx prod, dagvtx v, dag d, set todo)
tell whether the image produced by prod is definitely consummed by v given the global dag d and the s...
Definition: freia_spoc.c:1197
static void where_to_perform_operation(const dagvtx op, op_schedule *in0, op_schedule *in1, dag computed, set todo, op_schedule *out, hash_table wiring)
depending on available images (stage d, level, side 0/1) and vertex operation to perform ,...
Definition: freia_spoc.c:635
static void spoc_poc_conf(spoc_poc_t poc, string_buffer body, __attribute__((__unused__)) string_buffer tail, int stage, int side, dagvtx orig, hash_table hp)
generate a configuration for a POC (morpho) hardware component.
Definition: freia_spoc.c:190
static const spoc_alu_op_t ALU_OP[]
Definition: freia_spoc.c:66
static int max_stage(const op_schedule *in0, const op_schedule *in1)
Definition: freia_spoc.c:426
static void comment(string_buffer code, spoc_hardware_type hw, dagvtx v, int stage, int side, bool flip)
Definition: freia_spoc.c:52
static void freia_spoc_code_buildup(string module, string function_name, string_buffer code, const string_buffer head, const string_buffer body, const string_buffer tail, int n_im_out, int n_im_in, bool some_reductions, bool some_kernels, const string out0, const string out1, const string in0, const string in1)
build up final pipeline code from various pieces
Definition: freia_spoc.c:1128
static bool dag_spoc_not_implemented(dag d)
does this dag contains a spoc non implemented operation?
Definition: freia_spoc.c:2005
static void spoc_measure_conf(spoc_measure_t measure, __attribute__((__unused__)) string_buffer body, string_buffer tail, int stage, int side, dagvtx orig, hash_table hp)
there is no real configuration for the measures, the issue is just to fetch them.
Definition: freia_spoc.c:296
static const spoc_alu_op_t * get_spoc_alu_conf(spoc_alu_t alu)
Definition: freia_spoc.c:141
static void spoc_th_conf(string_buffer body, __attribute__((__unused__)) string_buffer tail, int stage, int side, dagvtx orig, hash_table hp)
generate a configuration for a threshold component.
Definition: freia_spoc.c:243
static int dagvtx_spoc_priority(const dagvtx *v1, const dagvtx *v2)
comparison function for sorting dagvtx in qsort, this is deep voodoo, because the priority has an imp...
Definition: freia_spoc.c:1775
static void find_first_available_component(hash_table wiring, int start_stage, int level, int side, int target_level, bool crossing, int *pstage, int *pside)
return the stage & side of the first component available after (start_stage, level,...
Definition: freia_spoc.c:545
static void set_mux(hash_table wiring, int stage, int mux)
Definition: freia_spoc.c:491
static void set_wiring(string_buffer code, int stage, int mux, _int value, hash_table wiring)
generate wiring code for mux if necessary.
Definition: freia_spoc.c:608
static list split_dag(dag initial, const set output_images)
split dag dall into a list of pipelinable dags which must be processed in that order (?...
Definition: freia_spoc.c:2103
static list dagvtx_spoc_priority_current
Definition: freia_spoc.c:1726
static bool check_mux_availibity(hash_table wiring, int stage, int mux)
Definition: freia_spoc.c:485
#define FREIA_SPOC_CALL_START
Definition: freia_spoc.h:202
#define FREIA_SPOC_CALL_REDUC
Definition: freia_spoc.h:211
#define spoc_depth_prop
Definition: freia_spoc.h:185
@ spoc_poc_erode
Definition: freia_spoc.h:147
@ spoc_poc_conv
Definition: freia_spoc.h:149
@ spoc_poc_unused
Definition: freia_spoc.h:146
@ spoc_poc_dilate
Definition: freia_spoc.h:148
spoc_alu_t
all SPoC ALU operations
Definition: freia_spoc.h:71
@ alu_sup_0cst
Definition: freia_spoc.h:111
@ alu_sub_1cst
Definition: freia_spoc.h:83
@ alu_div_10
Definition: freia_spoc.h:99
@ alu_or
Definition: freia_spoc.h:117
@ alu_mul_0cst
Definition: freia_spoc.h:96
@ alu_div_01
Definition: freia_spoc.h:98
@ alu_subsat_0cst
Definition: freia_spoc.h:88
@ alu_sub_0cst
Definition: freia_spoc.h:82
@ alu_abssub_1cst
Definition: freia_spoc.h:94
@ alu_inf_01
Definition: freia_spoc.h:107
@ alu_sup_01
Definition: freia_spoc.h:110
@ alu_copy_cst
Definition: freia_spoc.h:126
@ alu_subsat_01
Definition: freia_spoc.h:86
@ alu_sub_10
Definition: freia_spoc.h:81
@ alu_sup_1cst
Definition: freia_spoc.h:112
@ alu_add
Definition: freia_spoc.h:74
@ alu_xor_1cst
Definition: freia_spoc.h:122
@ alu_subsat_cst1
Definition: freia_spoc.h:91
@ alu_subsat_1cst
Definition: freia_spoc.h:89
@ alu_repcst_0
Definition: freia_spoc.h:130
@ alu_abssub
Definition: freia_spoc.h:92
@ alu_subsat_10
Definition: freia_spoc.h:87
@ alu_addsat
Definition: freia_spoc.h:77
@ alu_sub_cst0
Definition: freia_spoc.h:84
@ alu_and
Definition: freia_spoc.h:114
@ alu_add_1cst
Definition: freia_spoc.h:76
@ alu_sub_cst1
Definition: freia_spoc.h:85
@ alu_addsat_1cst
Definition: freia_spoc.h:79
@ alu_log2_1
Definition: freia_spoc.h:105
@ alu_log2_0
Definition: freia_spoc.h:104
@ alu_div_0cst
Definition: freia_spoc.h:100
@ alu_or_1cst
Definition: freia_spoc.h:119
@ alu_xor_0cst
Definition: freia_spoc.h:121
@ alu_unused
Definition: freia_spoc.h:72
@ alu_div_cst0
Definition: freia_spoc.h:102
@ alu_abssub_0cst
Definition: freia_spoc.h:93
@ alu_addsat_0cst
Definition: freia_spoc.h:78
@ alu_xor
Definition: freia_spoc.h:120
@ alu_div_1cst
Definition: freia_spoc.h:101
@ alu_mul_1cst
Definition: freia_spoc.h:97
@ alu_or_0cst
Definition: freia_spoc.h:118
@ alu_and_1cst
Definition: freia_spoc.h:116
@ alu_add_0cst
Definition: freia_spoc.h:75
@ alu_mask_1
Definition: freia_spoc.h:129
@ alu_repcst_1
Definition: freia_spoc.h:131
@ alu_inf_1cst
Definition: freia_spoc.h:109
@ alu_not_0
Definition: freia_spoc.h:123
@ alu_not_1
Definition: freia_spoc.h:124
@ alu_div_cst1
Definition: freia_spoc.h:103
@ alu_sub_01
Definition: freia_spoc.h:80
@ alu_mul
Definition: freia_spoc.h:95
@ alu_mask_0
Definition: freia_spoc.h:128
@ alu_and_0cst
Definition: freia_spoc.h:115
@ alu_subsat_cst0
Definition: freia_spoc.h:90
@ alu_inf_0cst
Definition: freia_spoc.h:108
spoc_measure_t
Definition: freia_spoc.h:61
@ measure_min
Definition: freia_spoc.h:65
@ measure_vol
Definition: freia_spoc.h:67
@ measure_none
Definition: freia_spoc.h:62
@ measure_max_coord
Definition: freia_spoc.h:64
@ measure_min_coord
Definition: freia_spoc.h:66
@ measure_max
Definition: freia_spoc.h:63
#define FREIA_SPOC_DECL
Definition: freia_spoc.h:194
spoc_hardware_type
Definition: freia_spoc.h:170
@ spoc_type_sni
Definition: freia_spoc.h:172
@ spoc_type_out
Definition: freia_spoc.h:180
@ 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_inp
Definition: freia_spoc.h:175
@ spoc_type_thr
Definition: freia_spoc.h:178
@ spoc_type_alu
Definition: freia_spoc.h:177
@ spoc_type_poc
Definition: freia_spoc.h:176
#define FREIA_SPOC_CALL_END
Definition: freia_spoc.h:216
#define pstatement_statement_p(x)
#define dagvtx_content(x)
#define vtxcontent_optype(x)
#define dag_outputs(x)
#define vtxcontent_out(x)
#define pstatement_statement(x)
#define dag_inputs(x)
#define dagvtx_succs(x)
#define vtxcontent_inputs(x)
#define dag_vertices(x)
#define vtxcontent_source(x)
#define DAGVTX(x)
DAGVTX.
void free(void *)
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_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
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
#define src(name, suf)
HPFC by Fabien Coelho, May 1993 and later...
Definition: compile.c:41
#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_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 _FALLTHROUGH_
Definition: misc-local.h:238
#define message_assert(msg, ex)
Definition: newgen_assert.h:47
char * i2a(int)
I2A (Integer TO Ascii) yields a string for a given Integer.
Definition: string.c:121
@ hash_int
Definition: newgen_hash.h:32
@ hash_pointer
Definition: newgen_hash.h:32
bool set_empty_p(const set)
tell whether set s is empty.
Definition: set.c:367
set set_assign_list(set, const list)
assigns a list contents to a set all duplicated elements are lost
Definition: set.c:474
bool set_intersection_p(const set, const set)
returns whether s1 n s2 <> 0 complexity of the intersection
Definition: set.c:288
set set_del_element(set, const set, const void *)
Definition: set.c:265
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
bool set_belong_p(const set, const void *)
Definition: set.c:194
set set_union(set, const set, const set)
Definition: set.c:211
@ set_pointer
Definition: newgen_set.h:44
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_append_sb(string_buffer, const string_buffer)
append the string buffer sb2 to string buffer sb.
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
#define _intFMT
Definition: newgen_types.h:57
intptr_t _int
_INT
Definition: newgen_types.h:53
static char * module
Definition: pips.c:74
list lparams
Array bounds.
Definition: reindexing.c:111
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 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
#define ENTITY(x)
ENTITY.
Definition: ri.h:2755
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
#define entity_undefined
Definition: ri.h:2761
#define call_arguments(x)
Definition: ri.h:711
#define level
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 bool ok
static size_t current
Definition: string.c:115
Definition: pip__tab.h:48
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
spoc_hw_t spoc
Definition: freia.h:89
code taken from http://fast-edge.googlecode.com and adapted to c99
Definition: erode_dilate.c:33
a data structure to describe a schedule for an operation
Definition: freia_spoc.c:398
entity image
Definition: freia_spoc.c:399
int used_stage
Definition: freia_spoc.c:408
spoc_hardware_type level
Definition: freia_spoc.c:402
bool just_used
Definition: freia_spoc.c:406
dagvtx producer
Definition: freia_spoc.c:400
spoc_hardware_type used_level
Definition: freia_spoc.c:409
ALU operation full description.
Definition: freia_spoc.h:136
spoc_alu_t op
Definition: freia_spoc.h:137
string setting
Definition: freia_spoc.h:139
spoc_alu_t flipped
Definition: freia_spoc.h:138
description of a SPoC hardware configuration should be precise enough to generate a full AIPO functio...
Definition: freia_spoc.h:160
spoc_poc_t poc[2]
Definition: freia_spoc.h:163
spoc_measure_t mes[2]
Definition: freia_spoc.h:166
spoc_alu_t alu
Definition: freia_spoc.h:164
spoc_poc_op_t op
Definition: freia_spoc.h:153
uint32_t connectivity
Definition: freia_spoc.h:154
@ empty
b1 < bj -> h1/hj = empty
Definition: union-local.h:64