PIPS
freia_spoc.c File Reference
#include <stdint.h>
#include <stdlib.h>
#include "genC.h"
#include "misc.h"
#include "freia.h"
#include "freia_spoc.h"
#include "linear.h"
#include "ri.h"
#include "effects.h"
#include "ri-util.h"
#include "effects-util.h"
#include "properties.h"
#include "freia_spoc_private.h"
#include "hwac.h"
+ Include dependency graph for freia_spoc.c:

Go to the source code of this file.

Data Structures

struct  op_schedule
 a data structure to describe a schedule for an operation More...
 

Macros

#define T   true
 
#define F   false
 

Functions

static void comment (string_buffer code, spoc_hardware_type hw, dagvtx v, int stage, int side, bool flip)
 
static const spoc_alu_op_tget_spoc_alu_conf (spoc_alu_t alu)
 
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. More...
 
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. More...
 
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. More...
 
static int spoc_measure_n_params (spoc_measure_t measure)
 
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. More...
 
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 More...
 
static void init_op_schedule (op_schedule *op, dagvtx v, int side)
 
static int max_stage (const op_schedule *in0, const op_schedule *in1)
 
static bool image_is_needed (dagvtx prod, dag d, set todo)
 is image needed? More...
 
static void print_op_schedule (FILE *out, const string name, const op_schedule *op)
 
static bool check_mux_availibity (hash_table wiring, int stage, int mux)
 
static void set_mux (hash_table wiring, int stage, int mux)
 
static bool check_wiring_output (hash_table wiring, int stage, int side)
 can I get out of stage on this side? More...
 
static _int component_index (int stage, int level, int side)
 
static void set_component (hash_table wiring, int stage, int level, int side)
 
static bool available_component (hash_table wiring, int stage, int level, int side)
 
static int find_first_crossing (hash_table wiring, int stage, int level)
 return the first stage after stage/level with both paths available More...
 
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, side) which is the source of the used image, for an operation of type target_level More...
 
static void set_wiring (string_buffer code, int stage, int mux, _int value, hash_table wiring)
 generate wiring code for mux if necessary. More...
 
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 , tell where to perform it. More...
 
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 More...
 
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. More...
 
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 More...
 
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 set of vertex still to be computed todo. More...
 
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. More...
 
static bool erode_alu_shared_p (vtxcontent c1, vtxcontent c2)
 ? = Morpho(I); ? = ALU(I, ?); More...
 
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 impact on correctness? that should not be the case as only computations allowed by dependencies are schedule. More...
 
static void live_update (dag d, dagvtx v, set sure, set maybe)
 update sure/maybe set of live images after computing vertex v that is the images that may be output from the pipeline. More...
 
static set output_arcs (dag d, set vs)
 returns an allocated set of vertices with live outputs. More...
 
static int number_of_output_arcs (dag d, set vs)
 how many output arcs from this set of vertices? More...
 
static bool convolution_33 (dagvtx v)
 
static bool dag_spoc_not_implemented (dag d)
 does this dag contains a spoc non implemented operation? More...
 
static dagvtx first_which_may_be_added (dag dall, set current, list lv, set sure, set maybe)
 return first vertex in the list which is compatible, or NULL if none. More...
 
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 (?) side effect: dall is more or less consummed... More...
 
list freia_spoc_compile_calls (string module, dag fulld, sequence sq, list ls, const hash_table occs, hash_table exchanges, const set output_images, FILE *helper_file, set helpers, int number)
 generate helpers for statements in ls of module output resulting functions in helper, which may be empty in some cases. More...
 

Variables

static const spoc_alu_op_t ALU_OP []
 
static list dagvtx_spoc_priority_computables = NIL
 current list of computable that may be used to know about the global context when comparing to vertices in "dagvtx_spoc_priority". More...
 
static list dagvtx_spoc_priority_current = NIL
 

Macro Definition Documentation

◆ F

#define F   false

Definition at line 50 of file freia_spoc.c.

◆ T

#define T   true

Definition at line 49 of file freia_spoc.c.

Function Documentation

◆ available_component()

static bool available_component ( hash_table  wiring,
int  stage,
int  level,
int  side 
)
static

Definition at line 522 of file freia_spoc.c.

524 {
525  _int index = component_index(stage, level, side);
526  return !hash_defined_p(wiring, (void *) index);
527 }
static _int component_index(int stage, int level, int side)
Definition: freia_spoc.c:504
bool hash_defined_p(const hash_table htp, const void *key)
true if key has e value in htp.
Definition: hash.c:484
intptr_t _int
_INT
Definition: newgen_types.h:53
#define level

References component_index(), hash_defined_p(), and level.

Referenced by find_first_available_component().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ basic_spoc_conf()

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 
)
static

basic configuration generation for a stage, depending on hw description

Returns
the number of arguments expected? what about their type?

Definition at line 360 of file freia_spoc.c.

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 }
string what_operation(const _int type)
Definition: freia-utils.c:499
#define sb_cat(args...)
Definition: freia.h:42
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 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 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 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
@ spoc_type_mes
Definition: freia_spoc.h:179
@ spoc_type_nop
Definition: freia_spoc.h:174
@ 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 pips_internal_error
Definition: misc-local.h:149
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

References spoc_hw_t::alu, spoc_hw_t::mes, pips_internal_error, spoc_hw_t::poc, sb_cat, spoc_alu_conf(), spoc_measure_conf(), spoc_poc_conf(), spoc_th_conf(), spoc_type_alu, spoc_type_inp, spoc_type_mes, spoc_type_nop, spoc_type_poc, spoc_type_thr, and what_operation().

Referenced by freia_spoc_pipeline().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_mux_availibity()

static bool check_mux_availibity ( hash_table  wiring,
int  stage,
int  mux 
)
static

Definition at line 485 of file freia_spoc.c.

486 {
487  _int index = 2 * (stage*4+mux) + 1; // odds
488  return !hash_defined_p(wiring, (void *) index);
489 }

References hash_defined_p().

Referenced by check_wiring_output(), and set_wiring().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_wiring_output()

static bool check_wiring_output ( hash_table  wiring,
int  stage,
int  side 
)
static

can I get out of stage on this side?

Definition at line 499 of file freia_spoc.c.

500 {
501  return check_mux_availibity(wiring, stage, side? 3: 0);
502 }
static bool check_mux_availibity(hash_table wiring, int stage, int mux)
Definition: freia_spoc.c:485

References check_mux_availibity().

Referenced by find_first_available_component(), find_first_crossing(), freia_spoc_pipeline(), generate_wiring(), and where_to_perform_operation().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ comment()

static void comment ( string_buffer  code,
spoc_hardware_type  hw,
dagvtx  v,
int  stage,
int  side,
bool  flip 
)
static

Definition at line 52 of file freia_spoc.c.

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 }
_int dagvtx_number(const dagvtx v)
returns the vertex number, i.e.
Definition: dag-utils.c:98
string dagvtx_operation(const dagvtx v)
Definition: dag-utils.c:134
char * i2a(int)
I2A (Integer TO Ascii) yields a string for a given Integer.
Definition: string.c:121

References dagvtx_number(), dagvtx_operation(), i2a(), sb_cat, spoc_type_alu, and what_operation().

Referenced by add_declaration_statement_here(), add_to_current_line(), build_call_STEP_WaitAll(), C_comment_to_text(), C_standard_comment_to_text(), clear_annotated_loop_nest(), close_current_line(), comment_string_p(), comments_dup(), compile_regions(), dagvtx_list_dot(), find_first_comment(), find_first_statement_comment(), gather_grid_dim(), generate_all_liveness_but(), generate_dynamic_liveness_for_primary(), generate_dynamic_liveness_management(), generate_io_statements_for_shared_arrays(), generate_remapping_include(), GENERATION(), generic_add_declaration_statement(), get_declaration_comments(), gpu_ify_statement(), io_filter(), make_layout_statement(), make_shared_statement(), MakeLabeledStatement(), number_of_use_greater_1(), parallelize_annotated_loop_nest(), prepend_comment(), remapping_compile(), remapping_stats(), spoc_alu_conf(), spoc_measure_conf(), spoc_poc_conf(), spoc_th_conf(), st_declaration_comment(), store_sc_text_line(), stub_var_decl(), text_loop_craft(), update_number_of_use(), and update_runtime_for_remapping().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ component_index()

static _int component_index ( int  stage,
int  level,
int  side 
)
static

Definition at line 504 of file freia_spoc.c.

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 }
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172

References level, pips_assert, spoc_type_alu, spoc_type_mes, and spoc_type_poc.

Referenced by available_component(), and set_component().

+ Here is the caller graph for this function:

◆ convolution_33()

static bool convolution_33 ( dagvtx  v)
static
Returns
whether it is a 3x3 convolution

Definition at line 1993 of file freia_spoc.c.

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 }
bool freia_convolution_p(dagvtx v)
is it the convolution special case?
Definition: freia-utils.c:1441
bool freia_convolution_width_height(dagvtx v, _int *pw, _int *ph, bool check)
get width & height of convolution
Definition: freia-utils.c:1449

◆ dag_spoc_not_implemented()

static bool dag_spoc_not_implemented ( dag  d)
static

does this dag contains a spoc non implemented operation?

Definition at line 2005 of file freia_spoc.c.

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 }
_int dagvtx_optype(const dagvtx v)
Definition: dag-utils.c:116
static bool convolution_33(dagvtx v)
Definition: freia_spoc.c:1993
@ spoc_type_sni
Definition: freia_spoc.h:172
#define dag_vertices(x)
#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

◆ dagvtx_spoc_priority()

static int dagvtx_spoc_priority ( const dagvtx v1,
const dagvtx v2 
)
static

comparison function for sorting dagvtx in qsort, this is deep voodoo, because the priority has an impact on correctness? that should not be the case as only computations allowed by dependencies are schedule.

non implemented functions are pushed late. tells v1 < v2 => -1 => v1 BEFORE v2

Definition at line 1775 of file freia_spoc.c.

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 }
void const char const char const int
static bool erode_alu_shared_p(vtxcontent c1, vtxcontent c2)
? = Morpho(I); ? = ALU(I, ?);
Definition: freia_spoc.c:1759
@ spoc_type_oth
Definition: freia_spoc.h:173
#define dagvtx_content(x)
#define vtxcontent_optype(x)
#define dagvtx_succs(x)
#define vtxcontent_inputs(x)
size_t gen_length(const list l)
Definition: list.c:150
#define pips_debug
these macros use the GNU extensions that allow variadic macros, including with an empty list.
Definition: misc-local.h:145
#define _intFMT
Definition: newgen_types.h:57

References _intFMT, dagvtx_content, dagvtx_number(), dagvtx_operation(), dagvtx_optype(), dagvtx_succs, erode_alu_shared_p(), FOREACH, gen_length(), int, pips_debug, spoc_type_mes, spoc_type_nop, spoc_type_oth, spoc_type_sni, vtxcontent_inputs, and vtxcontent_optype.

+ Here is the call graph for this function:

◆ erode_alu_shared_p()

static bool erode_alu_shared_p ( vtxcontent  c1,
vtxcontent  c2 
)
static

? = Morpho(I); ? = ALU(I, ?);

Definition at line 1759 of file freia_spoc.c.

1760 {
1761  return
1764  gen_length(vtxcontent_inputs(c2))==2 &&
1766 }
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
bool gen_in_list_p(const void *vo, const list lx)
tell whether vo belongs to lx
Definition: list.c:734
#define ENTITY(x)
ENTITY.
Definition: ri.h:2755

References CAR, ENTITY, gen_in_list_p(), gen_length(), spoc_type_alu, spoc_type_poc, vtxcontent_inputs, and vtxcontent_optype.

Referenced by dagvtx_spoc_priority().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ find_first_available_component()

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 
)
static

return the stage & side of the first component available after (start_stage, level, side) which is the source of the used image, for an operation of type target_level

Definition at line 545 of file freia_spoc.c.

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 }
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 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

References available_component(), check_wiring_output(), find_first_crossing(), level, pips_assert, and spoc_type_alu.

Referenced by where_to_perform_operation().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ find_first_crossing()

static int find_first_crossing ( hash_table  wiring,
int  stage,
int  level 
)
static

return the first stage after stage/level with both paths available

Definition at line 531 of file freia_spoc.c.

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 }

References check_wiring_output(), level, and spoc_type_alu.

Referenced by find_first_available_component().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ first_which_may_be_added()

static dagvtx first_which_may_be_added ( dag  dall,
set  current,
list  lv,
set  sure,
set  maybe 
)
static

return first vertex in the list which is compatible, or NULL if none.

Definition at line 2017 of file freia_spoc.c.

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 
2085  int narcs_with_v = number_of_output_arcs(dall, current);
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 }
list dag_vertex_preds(const dag d, const dagvtx target)
return target predecessor vertices as a list.
Definition: dag-utils.c:680
entity dagvtx_image(const dagvtx v)
return the produced image or NULL
Definition: dag-utils.c:82
static set output_arcs(dag d, set vs)
returns an allocated set of vertices with live outputs.
Definition: freia_spoc.c:1950
static int number_of_output_arcs(dag d, set vs)
how many output arcs from this set of vertices?
Definition: freia_spoc.c:1983
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
set set_assign_list(set, const list)
assigns a list contents to a set all duplicated elements are lost
Definition: set.c:474
set set_del_element(set, const set, const void *)
Definition: set.c:265
set set_intersection(set, const set, const set)
Definition: set.c:229
int set_size(const set)
returns the number of items in s.
Definition: set.c:359
void set_free(set)
Definition: set.c:332
bool set_inclusion_p(const set, const set)
return whether s1 \included s2
Definition: set.c:305
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
static size_t current
Definition: string.c:115
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_spoc_code_buildup()

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 
)
static

build up final pipeline code from various pieces

Parameters
module
function_nameto be generated
codeoutput
headinput, function parameters
bodyinput, pipeline stage initialization
tailinput, getting back reduction results
n_im_*number of in and out paramters to function
some_reductionsif there are
p_*variables sent and received from pipeline

Definition at line 1127 of file freia_spoc.c.

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 }
#define FREIA_DEFAULT_BPP
Definition: freia.h:53
#define FREIA_IMAGE
Definition: freia.h:52
#define FREIA_SPOC_CALL_START
Definition: freia_spoc.h:202
#define FREIA_SPOC_CALL_REDUC
Definition: freia_spoc.h:211
#define FREIA_SPOC_DECL
Definition: freia_spoc.h:194
#define FREIA_SPOC_CALL_END
Definition: freia_spoc.h:216
void string_buffer_append_sb(string_buffer, const string_buffer)
append the string buffer sb2 to string buffer sb.
static char * module
Definition: pips.c:74

References FREIA_DEFAULT_BPP, FREIA_IMAGE, FREIA_SPOC_CALL_END, FREIA_SPOC_CALL_REDUC, FREIA_SPOC_CALL_START, FREIA_SPOC_DECL, i2a(), module, sb_cat, and string_buffer_append_sb().

Referenced by freia_spoc_pipeline().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ freia_spoc_compile_calls()

list freia_spoc_compile_calls ( string  module,
dag  fulld,
sequence  sq,
list  ls,
const hash_table  occs,
hash_table  exchanges,
const set  output_images,
FILE *  helper_file,
set  helpers,
int  number 
)

generate helpers for statements in ls of module output resulting functions in helper, which may be empty in some cases.

freia_spoc.c

Parameters
module
lslist of statements for the dag (in reverse order)
helperoutput file
helperscreated functions
numbercurrent helper dag count
Returns
list of intermediate images to allocate

of expression

Parameters
moduleodule
fulldulld
sqq
lsof statements
occsccs
exchangesxchanges
output_imagesutput_images
helper_fileelper_file
helperselpers
numberumber

Definition at line 2246 of file freia_spoc.c.

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...
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 }
void free_dag(dag p)
list dag_fix_image_reuse(dag d, hash_table init, const hash_table occs)
fix intermediate image reuse in dag
Definition: dag-utils.c:2779
void freia_hack_fix_global_ins_outs(dag dfull, dag d)
catch some cases of missing outs between splits...
Definition: dag-utils.c:2166
void dag_dump(FILE *out, const string what, const dag d)
for dag debug
Definition: dag-utils.c:212
void freia_dag_optimize(dag d, hash_table exchanges, list *lbefore, list *lafter)
remove dead image operations.
Definition: dag-utils.c:1416
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
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
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
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
int freia_aipo_count(dag d, int *pa, int *pc)
Definition: freia-utils.c:1823
#define cat(args...)
Definition: freia.h:41
#define HELPER
Definition: freia.h:38
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 bool dag_spoc_not_implemented(dag d)
does this dag contains a spoc non implemented operation?
Definition: freia_spoc.c:2005
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
void free(void *)
hash_table hash_table_make(hash_key_type key_type, size_t size)
Definition: hash.c:294
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
@ hash_pointer
Definition: newgen_hash.h:32
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
list lparams
Array bounds.
Definition: reindexing.c:111
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
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
char * strdup()
#define ifdebug(n)
Definition: sg.c:47
internally defined structure.
Definition: string_buffer.c:47

Referenced by freia_compile().

+ Here is the caller graph for this function:

◆ freia_spoc_pipeline()

static _int freia_spoc_pipeline ( string  module,
string  helper,
string_buffer  code,
dag  dpipe,
list lparams,
const set  output_images 
)
static

generate a SPoC pipeline from a single DAG for module.

Parameters
modulecurrent
helpername of function to generate
codeoutput here
dpipedag to consider
lparamsparameters to call helper
Returns
number of output images

some side effects:

  • if there is an overflow, dpipe updated with remaining vertices.
  • accelerated statements are cleaned

I should have really done an allocation on a infinite pipeline, and then cut it, instead of this half measure to handle overflows, but that would change a lot of things to go back.

of entity

Definition at line 1240 of file freia_spoc.c.

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 }
int get_int_property(const string)
void free_dagvtx(dagvtx p)
static FILE * out
Definition: alias_check.c:128
void dag_remove_vertex(dag d, const dagvtx v)
remove vertex v from dag d.
Definition: dag-utils.c:570
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
_int dagvtx_opid(const dagvtx v)
Definition: dag-utils.c:121
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_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
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
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(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 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 void set_component(hash_table wiring, int stage, int level, int side)
Definition: freia_spoc.c:511
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 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
#define spoc_depth_prop
Definition: freia_spoc.h:185
@ spoc_type_out
Definition: freia_spoc.h:180
#define pstatement_statement_p(x)
#define dag_outputs(x)
#define vtxcontent_out(x)
#define pstatement_statement(x)
#define dag_inputs(x)
#define vtxcontent_source(x)
#define DAGVTX(x)
DAGVTX.
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
list gen_copy_seq(list l)
Copy a list structure.
Definition: list.c:501
#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 CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
@ hash_int
Definition: newgen_hash.h:32
bool set_empty_p(const set)
tell whether set s is empty.
Definition: set.c:367
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
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
#define call_arguments(x)
Definition: ri.h:711
FREIA API function name -> SPoC hardware description (and others?)
Definition: freia.h:71
spoc_hw_t spoc
Definition: freia.h:89
a data structure to describe a schedule for an operation
Definition: freia_spoc.c:398
entity image
Definition: freia_spoc.c:399
spoc_hardware_type level
Definition: freia_spoc.c:402
bool just_used
Definition: freia_spoc.c:406
dagvtx producer
Definition: freia_spoc.c:400

References _intFMT, basic_spoc_conf(), call_arguments, CAR, CDR, check_wiring_output(), CONS, dag_compute_outputs(), dag_inputs, dag_outputs, dag_remove_vertex(), dag_vertices, DAGVTX, dagvtx_content, dagvtx_number(), dagvtx_opid(), dagvtx_optype(), dagvtx_succs, ENTITY, entity_local_name(), FOREACH, free_dagvtx(), freia_add_image_arguments(), freia_extract_params(), freia_spoc_code_buildup(), freia_statement_to_call(), gen_copy_seq(), gen_free_list(), gen_in_list_p(), gen_length(), gen_nconc(), gen_nreverse(), gen_remove(), generate_wiring(), get_freia_api(), get_int_property(), hash_int, hash_pointer, hash_table_free(), hash_table_make(), hwac_kill_statement(), i2a(), op_schedule::image, image_is_needed(), init_op_schedule(), is_consummed_by_vertex(), op_schedule::just_used, op_schedule::level, lparams, module, NIL, out, pips_assert, pips_debug, pips_internal_error, op_schedule::producer, pstatement_statement, pstatement_statement_p, sb_cat, set_add_element(), set_assign_list(), set_belong_p(), set_component(), set_del_element(), set_difference(), set_empty_p(), SET_FOREACH, set_free(), set_make(), set_pointer, set_size(), op_schedule::side, freia_api_t::spoc, spoc_depth_prop, spoc_type_mes, spoc_type_out, spoc_type_poc, op_schedule::stage, string_buffer_free(), string_buffer_make(), op_schedule::used, vtxcontent_optype, vtxcontent_out, vtxcontent_source, and where_to_perform_operation().

+ Here is the call graph for this function:

◆ generate_wiring()

static void generate_wiring ( string_buffer  code,
op_schedule in,
op_schedule out,
hash_table  wiring 
)
static

generate wire code from in to out, record choices in wiring.

Definition at line 948 of file freia_spoc.c.

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 }
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
#define _FALLTHROUGH_
Definition: misc-local.h:238

References _FALLTHROUGH_, _intFMT, CAR, check_wiring_output(), dagvtx_content, dagvtx_number(), dagvtx_operation(), dagvtx_optype(), ENTITY, entity_local_name(), free(), gen_length(), generate_wiring_stage(), i2a(), op_schedule::image, op_schedule::level, out, pips_assert, pips_debug, pips_internal_error, sb_cat, set_component(), op_schedule::side, spoc_type_alu, spoc_type_inp, spoc_type_mes, spoc_type_nop, spoc_type_out, spoc_type_poc, spoc_type_thr, op_schedule::stage, strdup(), vtxcontent_inputs, and what_operation().

Referenced by freia_spoc_pipeline().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ generate_wiring_stage()

static void generate_wiring_stage ( string_buffer  code,
int  stage,
int  in_side,
int  out_side,
hash_table  wiring 
)
static

all possible wirings at one stage

Definition at line 903 of file freia_spoc.c.

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 }
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

References pips_assert, pips_debug, pips_internal_error, and set_wiring().

Referenced by generate_wiring().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_spoc_alu_conf()

static const spoc_alu_op_t* get_spoc_alu_conf ( spoc_alu_t  alu)
static

Definition at line 141 of file freia_spoc.c.

142 {
143  return &ALU_OP[alu];
144 }
static const spoc_alu_op_t ALU_OP[]
Definition: freia_spoc.c:66

References ALU_OP.

Referenced by spoc_alu_conf().

+ Here is the caller graph for this function:

◆ image_is_needed()

static bool image_is_needed ( dagvtx  prod,
dag  d,
set  todo 
)
static

is image needed?

Definition at line 446 of file freia_spoc.c.

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 }

References _intFMT, dag_outputs, dag_vertex_preds(), dagvtx_number(), gen_free_list(), gen_in_list_p(), NIL, pips_debug, and SET_FOREACH.

Referenced by freia_spoc_pipeline(), and where_to_perform_operation().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ init_op_schedule()

static void init_op_schedule ( op_schedule op,
dagvtx  v,
int  side 
)
static

Definition at line 412 of file freia_spoc.c.

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 }
int used_stage
Definition: freia_spoc.c:408
spoc_hardware_type used_level
Definition: freia_spoc.c:409

References dagvtx_image(), op_schedule::flip, op_schedule::image, op_schedule::just_used, op_schedule::level, op_schedule::producer, op_schedule::side, spoc_type_inp, op_schedule::stage, op_schedule::used, op_schedule::used_level, and op_schedule::used_stage.

Referenced by freia_spoc_pipeline().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ is_consummed_by_vertex()

static bool is_consummed_by_vertex ( dagvtx  prod,
dagvtx  v,
dag  d,
set  todo 
)
static

tell whether the image produced by prod is definitely consummed by v given the global dag d and the set of vertex still to be computed todo.

Definition at line 1197 of file freia_spoc.c.

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 }
bool set_intersection_p(const set, const set)
returns whether s1 n s2 <> 0 complexity of the intersection
Definition: set.c:288

References _intFMT, dag_outputs, dagvtx_number(), dagvtx_succs, gen_in_list_p(), pips_debug, set_assign_list(), set_del_element(), set_free(), set_intersection_p(), set_make(), and set_pointer.

Referenced by freia_spoc_pipeline().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ live_update()

static void live_update ( dag  d,
dagvtx  v,
set  sure,
set  maybe 
)
static

update sure/maybe set of live images after computing vertex v that is the images that may be output from the pipeline.

this is voodoo...

Definition at line 1885 of file freia_spoc.c.

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 }
bool dagvtx_other_stuff_p(const dagvtx v)
a vertex with a non AIPO or image related statement.
Definition: dag-utils.c:76
bool list_in_set_p(const list, const set)
Definition: set.c:201
set set_clear(set)
Assign the empty set to s s := {}.
Definition: set.c:326
set set_append_list(set, const list)
add list l items to set s, which is returned.
Definition: set.c:460
#define entity_undefined
Definition: ri.h:2761

◆ max_stage()

static int max_stage ( const op_schedule in0,
const op_schedule in1 
)
static

Definition at line 426 of file freia_spoc.c.

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 }

References op_schedule::image, and op_schedule::stage.

Referenced by where_to_perform_operation().

+ Here is the caller graph for this function:

◆ number_of_output_arcs()

static int number_of_output_arcs ( dag  d,
set  vs 
)
static

how many output arcs from this set of vertices?

Definition at line 1983 of file freia_spoc.c.

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 }

◆ output_arcs()

static set output_arcs ( dag  d,
set  vs 
)
static

returns an allocated set of vertices with live outputs.

Definition at line 1950 of file freia_spoc.c.

1951 {
1952  set out_nodes = set_make(set_pointer);
1953  // direct output nodes
1954  SET_FOREACH(dagvtx, v, vs)
1955  {
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 }

◆ print_op_schedule()

static void print_op_schedule ( FILE *  out,
const string  name,
const op_schedule op 
)
static

Definition at line 472 of file freia_spoc.c.

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 }

References _intFMT, dagvtx_number(), dagvtx_operation(), entity_local_name(), op_schedule::flip, fprintf(), op_schedule::image, op_schedule::level, out, op_schedule::producer, op_schedule::side, spoc_type_alu, op_schedule::stage, op_schedule::used, op_schedule::used_level, op_schedule::used_stage, and what_operation().

Referenced by where_to_perform_operation().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_component()

static void set_component ( hash_table  wiring,
int  stage,
int  level,
int  side 
)
static

Definition at line 511 of file freia_spoc.c.

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 }

References component_index(), hash_put(), level, spoc_type_mes, spoc_type_poc, and spoc_type_thr.

Referenced by freia_spoc_pipeline(), and generate_wiring().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_mux()

static void set_mux ( hash_table  wiring,
int  stage,
int  mux 
)
static

Definition at line 491 of file freia_spoc.c.

492 {
493  _int index = 2 * (stage*4+mux) + 1; // odds
494  hash_put(wiring, (void *) index, (void *) index);
495 }

References hash_put().

Referenced by set_wiring().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_wiring()

static void set_wiring ( string_buffer  code,
int  stage,
int  mux,
_int  value,
hash_table  wiring 
)
static

generate wiring code for mux if necessary.

Parameters
codegenerated
stagestage under consideration
muxmultiplexer to set
valuestatus for the multiplexer
wiringalready performed wiring to check for double settings.

Definition at line 608 of file freia_spoc.c.

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 }
static void set_mux(hash_table wiring, int stage, int mux)
Definition: freia_spoc.c:491

References _intFMT, check_mux_availibity(), free(), i2a(), pips_assert, pips_debug, sb_cat, set_mux(), and strdup().

Referenced by generate_wiring_stage().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ split_dag()

static list split_dag ( dag  initial,
const set  output_images 
)
static

split dag dall into a list of pipelinable dags which must be processed in that order (?) side effect: dall is more or less consummed...

of dags

Definition at line 2103 of file freia_spoc.c.

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
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,
2139  set_fprint(stderr, "current", current,
2141  set_fprint(stderr, "avails", avails,
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);
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));
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));
2200  }
2201  dag_compute_outputs(nd, NULL, output_images, NIL, false);
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 }
dag make_dag(list a1, list a2, list a3)
dag copy_dag(dag p)
DAG.
static int count
Definition: SDG.c:519
void dag_cleanup_other_statements(dag d)
remove unneeded statements? you must know they are really un-needed!
Definition: dag-utils.c:2191
int dag_computation_count(const dag d)
return the number of actual operations in dag d.
Definition: dag-utils.c:665
void dagvtx_nb_dump(FILE *out, const string what, const list l)
Definition: dag-utils.c:176
dagvtx copy_dagvtx_norec(dagvtx v)
copy a vertex, but without its successors.
Definition: dag-utils.c:611
list dag_computable_vertices(dag d, const set computed, const set maybe, const set currents)
return the vertices which may be computed from the list of available images, excluding vertices in ex...
Definition: dag-utils.c:2307
string dagvtx_to_string(const dagvtx v)
dag-utils.c
Definition: dag-utils.c:49
bool single_image_assignement_p(dag d)
??? I'm unsure about what happens to dead code in the pipeline...
Definition: dag-utils.c:2217
void dag_append_vertex(dag d, dagvtx nv)
append new vertex nv to dag d.
Definition: dag-utils.c:632
static 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 void live_update(dag d, dagvtx v, set sure, set maybe)
update sure/maybe set of live images after computing vertex v that is the images that may be output f...
Definition: freia_spoc.c:1885
static dagvtx first_which_may_be_added(dag dall, set current, list lv, set sure, set maybe)
return first vertex in the list which is compatible, or NULL if none.
Definition: freia_spoc.c:2018
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 list dagvtx_spoc_priority_current
Definition: freia_spoc.c:1726
if(!(yy_init))
Definition: genread_lex.c:1029
void gen_sort_list(list l, gen_cmp_func_t compare)
Sorts a list of gen_chunks in place, to avoid allocations...
Definition: list.c:796
#define pips_user_warning
Definition: misc-local.h:146
set set_assign(set, const set)
Assign a set with the content of another set.
Definition: set.c:129
void set_fprint(FILE *, string, const set, gen_string_func_t)
print set s to file stream out.
Definition: set.c:524
string(* gen_string_func_t)(const void *)
Definition: newgen_types.h:111

◆ spoc_alu_conf()

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 
)
static

generate a configuration for the ALU hardware component.

Definition at line 148 of file freia_spoc.c.

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 }
list freia_get_vertex_params(const dagvtx v)
Definition: freia-utils.c:578
static void comment(string_buffer code, spoc_hardware_type hw, dagvtx v, int stage, int side, bool flip)
Definition: freia_spoc.c:52
static const spoc_alu_op_t * get_spoc_alu_conf(spoc_alu_t alu)
Definition: freia_spoc.c:141
spoc_alu_t
all SPoC ALU operations
Definition: freia_spoc.h:71
@ alu_unused
Definition: freia_spoc.h:72
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
#define message_assert(msg, ex)
Definition: newgen_assert.h:47
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
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

References alu_unused, CAR, comment(), EXPRESSION, spoc_alu_op_t::flipped, free(), freia_get_vertex_params(), get_spoc_alu_conf(), hash_get(), i2a(), message_assert, spoc_alu_op_t::op, sb_cat, spoc_alu_op_t::setting, spoc_type_alu, strdup(), and spoc_alu_op_t::use_cst.

Referenced by basic_spoc_conf().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ spoc_measure_conf()

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 
)
static

there is no real configuration for the measures, the issue is just to fetch them.

Definition at line 295 of file freia_spoc.c.

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 }
static int spoc_measure_n_params(spoc_measure_t measure)
Definition: freia_spoc.c:278
@ measure_min
Definition: freia_spoc.h:65
@ measure_vol
Definition: freia_spoc.h:67
@ measure_max_coord
Definition: freia_spoc.h:64
@ measure_min_coord
Definition: freia_spoc.h:66
@ measure_max
Definition: freia_spoc.h:63

References CAR, cat, CDR, comment(), EXPRESSION, free(), freia_get_vertex_params(), gen_length(), hash_get(), i2a(), measure_max, measure_max_coord, measure_min, measure_min_coord, measure_vol, pips_assert, pips_internal_error, sb_cat, spoc_measure_n_params(), spoc_type_mes, and strdup().

Referenced by basic_spoc_conf().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ spoc_measure_n_params()

static int spoc_measure_n_params ( spoc_measure_t  measure)
static

Definition at line 278 of file freia_spoc.c.

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 }
@ measure_none
Definition: freia_spoc.h:62

References measure_max_coord, measure_min_coord, and measure_none.

Referenced by spoc_measure_conf().

+ Here is the caller graph for this function:

◆ spoc_poc_conf()

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 
)
static

generate a configuration for a POC (morpho) hardware component.

Definition at line 189 of file freia_spoc.c.

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 }
@ 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_poc_op_t op
Definition: freia_spoc.h:153
uint32_t connectivity
Definition: freia_spoc.h:154

References CAR, comment(), spoc_poc_t::connectivity, EXPRESSION, free(), freia_get_vertex_params(), hash_get(), i2a(), spoc_poc_t::op, pips_internal_error, sb_cat, spoc_poc_conv, spoc_poc_dilate, spoc_poc_erode, spoc_poc_unused, spoc_type_poc, and strdup().

Referenced by basic_spoc_conf().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ spoc_th_conf()

static void spoc_th_conf ( string_buffer  body,
__attribute__((__unused__)) string_buffer  tail,
int  stage,
int  side,
dagvtx  orig,
hash_table  hp 
)
static

generate a configuration for a threshold component.

Definition at line 242 of file freia_spoc.c.

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 }

References CAR, CDR, comment(), EXPRESSION, free(), freia_get_vertex_params(), gen_length(), hash_get(), i2a(), pips_assert, sb_cat, spoc_type_thr, and strdup().

Referenced by basic_spoc_conf().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ where_to_perform_operation()

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 
)
static

depending on available images (stage d, level, side 0/1) and vertex operation to perform , tell where to perform it.

some voodoo again...

Definition at line 634 of file freia_spoc.c.

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 }
static void print_op_schedule(FILE *out, const string name, const op_schedule *op)
Definition: freia_spoc.c:472
static int max_stage(const op_schedule *in0, const op_schedule *in1)
Definition: freia_spoc.c:426
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
spoc_hardware_type
Definition: freia_spoc.h:170

References _intFMT, CAR, check_wiring_output(), dagvtx_content, dagvtx_number(), dagvtx_operation(), ENTITY, entity_local_name(), entity_undefined, find_first_available_component(), gen_length(), ifdebug, op_schedule::image, image_is_needed(), int, op_schedule::just_used, level, op_schedule::level, max_stage(), out, pips_assert, pips_debug, pips_internal_error, print_op_schedule(), op_schedule::producer, op_schedule::side, spoc_type_alu, spoc_type_inp, spoc_type_mes, spoc_type_nop, spoc_type_poc, spoc_type_thr, op_schedule::stage, op_schedule::used, op_schedule::used_level, op_schedule::used_stage, vtxcontent_inputs, vtxcontent_optype, vtxcontent_out, and what_operation().

Referenced by freia_spoc_pipeline().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ ALU_OP

const spoc_alu_op_t ALU_OP[]
static

Definition at line 66 of file freia_spoc.c.

Referenced by get_spoc_alu_conf().

◆ dagvtx_spoc_priority_computables

list dagvtx_spoc_priority_computables = NIL
static

current list of computable that may be used to know about the global context when comparing to vertices in "dagvtx_spoc_priority".

Definition at line 1724 of file freia_spoc.c.

◆ dagvtx_spoc_priority_current

list dagvtx_spoc_priority_current = NIL
static

Definition at line 1726 of file freia_spoc.c.