PandA-2024.02
allocation_information.cpp
Go to the documentation of this file.
1 /*
2  *
3  * _/_/_/ _/_/ _/ _/ _/_/_/ _/_/
4  * _/ _/ _/ _/ _/_/ _/ _/ _/ _/ _/
5  * _/_/_/ _/_/_/_/ _/ _/_/ _/ _/ _/_/_/_/
6  * _/ _/ _/ _/ _/ _/ _/ _/ _/
7  * _/ _/ _/ _/ _/ _/_/_/ _/ _/
8  *
9  * ***********************************************
10  * PandA Project
11  * URL: http://panda.dei.polimi.it
12  * Politecnico di Milano - DEIB
13  * System Architectures Group
14  * ***********************************************
15  * Copyright (C) 2004-2024 Politecnico di Milano
16  *
17  * This file is part of the PandA framework.
18  *
19  * The PandA framework is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 3 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program. If not, see <http://www.gnu.org/licenses/>.
31  *
32  */
42 
43 #include "Parameter.hpp" // for ParameterConstRef
44 #include "allocation.hpp" // for Allocation_MinMax, Allocation_Mi...
45 #include "allocation_constants.hpp" // for NUM_CST_allocation_default_conne...
46 #include "area_info.hpp"
47 #include "basic_block.hpp"
48 #include "behavioral_helper.hpp" // for OpGraphConstRef, tree_nodeRef
49 #include "custom_map.hpp"
50 #include "custom_set.hpp"
51 #include "dbgPrintHelper.hpp" // for DEBUG_LEVEL_VERY_PEDANTIC, INDEN...
52 #include "exceptions.hpp" // for THROW_ASSERT, THROW_UNREACHABLE
53 #include "ext_tree_node.hpp"
54 #include "fu_binding.hpp" // for fu_binding, fu_binding::UNKNOWN
55 #include "hls.hpp"
56 #include "hls_constraints.hpp"
57 #include "hls_device.hpp"
58 #include "hls_manager.hpp" // for HLS_manager, HLS_manager::io_bin...
59 #include "hls_step.hpp" // for hlsRef
60 #include "math_function.hpp" // for ceil_pow2
61 #include "memory.hpp"
62 #include "schedule.hpp" // for ControlStep, AbsControlStep, HLS...
64 #include "string_manipulation.hpp" // for STR GET_CLASS
65 #include "structural_manager.hpp"
66 #include "technology_manager.hpp" // for LIBRARY_STD_FU
67 #include "technology_node.hpp" // for technology_nodeRef, MEMORY_CTRL_...
68 #include "time_info.hpp"
69 #include "tree_basic_block.hpp"
70 #include "tree_helper.hpp"
71 #include "tree_manager.hpp"
72 #include "tree_node.hpp" // for GET_NODE, GET_CONST_NODE, TreeNo...
73 #include "tree_reindex.hpp"
74 #include "typed_node_info.hpp" // for GET_NAME
75 #include <algorithm>
76 #include <cmath> // for exp, ceil
77 #include <limits> // for numeric_limits
78 #include <tuple>
79 
80 const std::pair<const CustomMap<unsigned long long, CustomUnorderedMapStable<unsigned int, double>>&,
83 {
86  if(mux_timing_db.empty() || mux_area_db.empty())
87  {
88  // const unsigned int debug_level = 0;
89  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Initializing mux databases");
91  const technology_managerRef TM = allocation_information->hls_manager->get_HLS_device()->get_technology_manager();
93  THROW_ASSERT(f_unit_mux, "Library miss component: " + std::string(MUX_N_TO_1));
94  auto* fu_br = GetPointer<functional_unit_template>(f_unit_mux);
95  technology_nodeRef op_mux_node = GetPointer<functional_unit>(fu_br->FU)->get_operation(MUX_N_TO_1);
96  auto* op_mux = GetPointer<operation>(op_mux_node);
97  std::string temp_portsize_parameters = op_mux->portsize_parameters;
98  std::vector<unsigned int> mux_precisions;
99  mux_precisions.push_back(1);
100  mux_precisions.push_back(8);
101  mux_precisions.push_back(16);
102  mux_precisions.push_back(32);
103  mux_precisions.push_back(64);
104  std::vector<std::string> parameters_split = SplitString(temp_portsize_parameters, "|");
105  THROW_ASSERT(parameters_split.size() > 0, "unexpected portsize_parameter format");
106  for(auto module_prec : mux_precisions)
107  {
108  for(auto& el_indx : parameters_split)
109  {
110  std::vector<std::string> parameters_pairs = SplitString(el_indx, ":");
111  if(parameters_pairs[0] == "*")
112  {
113  temp_portsize_parameters = parameters_pairs[1];
114  break;
115  }
116  else if(static_cast<unsigned>(std::stoul(parameters_pairs[0])) == module_prec)
117  {
118  temp_portsize_parameters = parameters_pairs[1];
119  break;
120  }
121  }
122  THROW_ASSERT(temp_portsize_parameters != "",
123  "expected some portsize0_parameters for the the template operation");
124  std::vector<std::string> portsize_parameters = SplitString(temp_portsize_parameters, ",");
125  for(const auto& n_inputs : portsize_parameters)
126  {
127  const technology_nodeRef fu_cur_obj =
128  allocation_information->hls_manager->get_HLS_device()->get_technology_manager()->get_fu(
129  std::string(MUX_N_TO_1) + "_" + STR(module_prec) + "_" + STR(module_prec) + "_" + STR(module_prec) +
130  "_" + n_inputs,
132  if(fu_cur_obj)
133  {
134  const functional_unit* fu_cur = GetPointer<functional_unit>(fu_cur_obj);
135  area_infoRef a_m = fu_cur->area_m;
136  auto cur_area = a_m->get_resource_value(area_info::SLICE_LUTS);
137  if(cur_area == 0.0)
138  {
139  cur_area = a_m->get_area_value();
140  }
141  auto n_inputs_value = static_cast<unsigned>(std::stoul(n_inputs));
142  mux_area_db[module_prec][n_inputs_value] = cur_area;
143  auto* fu_cur_operation = GetPointer<operation>(fu_cur->get_operation(MUX_N_TO_1));
144  mux_timing_db[module_prec][n_inputs_value] = fu_cur_operation->time_m->get_execution_time() *
145  allocation_information->time_multiplier *
146  allocation_information->mux_time_multiplier;
147  }
148  }
149  }
150 #define MAX_MUX_N_INPUTS 65
151  for(auto module_prec : mux_precisions)
152  {
153  if(mux_area_db.find(module_prec) == mux_area_db.end())
154  {
155  THROW_ASSERT(mux_timing_db.find(module_prec) == mux_timing_db.end(), "unexpected condition");
156  for(unsigned int n_ins = 2; n_ins <= MAX_MUX_N_INPUTS; ++n_ins)
157  {
158  unsigned int n_levels;
159  for(n_levels = 1; n_ins > (1ULL << n_levels); ++n_levels)
160  {
161  ;
162  }
163  mux_area_db[module_prec][n_ins] = (n_ins - 1) * allocation_information->mux_area_unit_raw(module_prec);
164  mux_timing_db[module_prec][n_ins] = n_levels *
165  (allocation_information->mux_time_unit_raw(module_prec) +
166  allocation_information->get_setup_hold_time()) *
167  allocation_information->mux_time_multiplier;
168  }
169  }
170  else
171  {
172  THROW_ASSERT(mux_timing_db.find(module_prec) != mux_timing_db.end(), "unexpected condition");
173  THROW_ASSERT(mux_area_db.find(module_prec)->second.find(2) != mux_area_db.find(module_prec)->second.end(),
174  "unexpected condition");
175  THROW_ASSERT(mux_timing_db.find(module_prec)->second.find(2) !=
176  mux_timing_db.find(module_prec)->second.end(),
177  "unexpected condition");
178  unsigned int prev_non_null = 2;
179  for(unsigned int n_ins = 3; n_ins <= MAX_MUX_N_INPUTS; ++n_ins)
180  {
181  if(mux_area_db.find(module_prec)->second.find(n_ins) != mux_area_db.find(module_prec)->second.end())
182  {
183  if(prev_non_null + 1 != n_ins)
184  {
185  for(; prev_non_null + 1 < n_ins; ++prev_non_null)
186  {
187  mux_area_db[module_prec][prev_non_null + 1] =
188  mux_area_db.find(module_prec)->second.find(prev_non_null)->second +
189  (mux_area_db.find(module_prec)->second.find(n_ins)->second -
190  mux_area_db.find(module_prec)->second.find(prev_non_null)->second) /
191  (n_ins - prev_non_null);
192  mux_timing_db[module_prec][prev_non_null + 1] =
193  mux_timing_db.find(module_prec)->second.find(prev_non_null)->second +
194  (mux_timing_db.find(module_prec)->second.find(n_ins)->second -
195  mux_timing_db.find(module_prec)->second.find(prev_non_null)->second) /
196  (n_ins - prev_non_null);
197  }
198  }
199  prev_non_null = n_ins;
200  }
201  }
202  }
203  }
204  THROW_ASSERT(mux_area_db.find(64) != mux_area_db.end(), "unexpected condition");
205  THROW_ASSERT(!mux_area_db.at(64).empty(), "unexpected condition");
206  THROW_ASSERT(mux_timing_db.find(64) != mux_timing_db.end(), "unexpected condition");
207  THROW_ASSERT(!mux_timing_db.at(64).empty(), "unexpected condition");
208  mux_area_db[128].insert(mux_area_db.at(64).begin(), mux_area_db.at(64).end());
209  mux_timing_db[128].insert(mux_timing_db.at(64).begin(), mux_timing_db.at(64).end());
210  // THROW_WARNING(STR(mux_timing_db.size()));
211  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Initialized mux databases");
212  }
213  return std::pair<const CustomMap<unsigned long long, CustomUnorderedMapStable<unsigned int, double>>&,
215  mux_area_db);
216 }
217 
218 const std::tuple<const std::vector<unsigned int>&, const std::vector<unsigned int>&>
220 {
221  static std::vector<unsigned int> DSP_x_db;
222  static std::vector<unsigned int> DSP_y_db;
223  if(!(DSP_x_db.size() || DSP_y_db.size()))
224  {
226  const auto hls_d = allocation_information->hls_manager->get_HLS_device();
227  if(hls_d->has_parameter("DSPs_x_sizes"))
228  {
229  THROW_ASSERT(hls_d->has_parameter("DSPs_y_sizes"), "device description is not complete");
230  auto DSPs_x_sizes = hls_d->get_parameter<std::string>("DSPs_x_sizes");
231  auto DSPs_y_sizes = hls_d->get_parameter<std::string>("DSPs_y_sizes");
232  std::vector<std::string> DSPs_x_sizes_vec = SplitString(DSPs_x_sizes, ",");
233  std::vector<std::string> DSPs_y_sizes_vec = SplitString(DSPs_y_sizes, ",");
234  size_t n_elements = DSPs_x_sizes_vec.size();
235  DSP_x_db.resize(n_elements);
236  DSP_y_db.resize(n_elements);
237  for(size_t index = 0; index < n_elements; ++index)
238  {
239  DSP_x_db[index] = static_cast<unsigned>(std::stoul(DSPs_x_sizes_vec[index]));
240  DSP_y_db[index] = static_cast<unsigned>(std::stoul(DSPs_y_sizes_vec[index]));
241  }
242  }
243  }
244  return std::tuple<const std::vector<unsigned int>&, const std::vector<unsigned int>&>(DSP_x_db, DSP_y_db);
245 }
246 
247 static const double epsilon = 0.000000001;
248 
249 AllocationInformation::AllocationInformation(const HLS_managerRef _hls_manager, const unsigned int _function_index,
250  const ParameterConstRef _parameters)
251  : HLSFunctionIR(_hls_manager, _function_index, _parameters), address_bitsize(_hls_manager->Rget_address_bitsize())
252 {
253  debug_level = _parameters->get_class_debug_level(GET_CLASS(*this));
254 }
255 
257 
259 {
260  return op->time_m->get_execution_time() * time_multiplier;
261 }
262 
264 {
265  return op->time_m->get_stage_period() * time_multiplier;
266 }
267 
268 std::pair<std::string, std::string> AllocationInformation::get_fu_name(unsigned int id) const
269 {
270  THROW_ASSERT(id_to_fu_names.find(id) != id_to_fu_names.end(), "Functional unit name not stored!");
271  return id_to_fu_names.find(id)->second;
272 }
273 
275 {
276  return static_cast<unsigned int>(list_of_FU.size());
277 }
278 
279 unsigned int AllocationInformation::get_number_fu(unsigned int fu_name) const
280 {
281  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
282  return tech_constraints[fu_name];
283 }
284 
286 {
287  return can_implement_set(op_graph->CGetOpNodeInfo(v)->GetNodeId());
288 }
289 
291 {
292  const auto entry_string_cst = std::string("Entry");
293  const auto exit_string_cst = std::string("Exit");
294  const auto node_operation = [&]() -> std::string {
295  if(v == ENTRY_ID)
296  {
297  return entry_string_cst;
298  }
299  if(v == EXIT_ID)
300  {
301  return exit_string_cst;
302  }
303  return GetPointer<const gimple_node>(TreeM->CGetTreeNode(v))->operation;
304  }();
305  const auto vtf_it = node_id_to_fus.find(std::pair<unsigned int, std::string>(v, node_operation));
306  THROW_ASSERT(vtf_it != node_id_to_fus.end(), "unmapped operation " + TreeM->CGetTreeNode(v)->ToString());
307  return vtf_it->second;
308 }
309 
310 bool AllocationInformation::CanImplementSetNotEmpty(const unsigned int v) const
311 {
312  if(v == ENTRY_ID)
313  {
314  return true;
315  }
316  if(v == EXIT_ID)
317  {
318  return true;
319  }
320  const auto node_operation = GetPointer<const gimple_node>(TreeM->CGetTreeNode(v))->operation;
321  return node_id_to_fus.find(std::pair<unsigned int, std::string>(v, node_operation)) != node_id_to_fus.end();
322 }
323 
324 double AllocationInformation::get_execution_time(const unsigned int fu_name, const vertex v,
325  const OpGraphConstRef g) const
326 {
327  return get_execution_time(fu_name, g->CGetOpNodeInfo(v)->GetNodeId());
328 }
329 
330 double AllocationInformation::get_execution_time(const unsigned int fu_name, unsigned int v) const
331 {
332  if(v == ENTRY_ID || v == EXIT_ID)
333  {
334  return 0.0;
335  }
336  THROW_ASSERT(can_implement_set(v).find(fu_name) != can_implement_set(v).end(),
337  "This function (" + get_string_name(fu_name) + ") cannot implement the operation " + STR(v));
338  if(!has_to_be_synthetized(fu_name))
339  {
340  return 0.0;
341  }
342  const auto operation_name =
343  tree_helper::NormalizeTypename(GetPointer<const gimple_node>(TreeM->CGetTreeNode(v))->operation);
344  technology_nodeRef node_op = GetPointer<functional_unit>(list_of_FU[fu_name])->get_operation(operation_name);
345  THROW_ASSERT(GetPointer<operation>(node_op)->time_m,
346  "Timing information not specified for unit " + id_to_fu_names.find(fu_name)->second.first);
347  double clock_budget = HLS_C->get_clock_period() * HLS_C->get_clock_period_resource_fraction();
348  auto n_cycles = GetPointer<operation>(node_op)->time_m->get_cycles();
349  if(n_cycles)
350  {
351  const double stage_time = [&]() -> double {
353  if(GetPointer<functional_unit>(list_of_FU[fu_name])->component_timing_alias != "")
354  {
355  std::string component_name = GetPointer<functional_unit>(list_of_FU[fu_name])->component_timing_alias;
356  std::string library = HLS_D->get_technology_manager()->get_library(component_name);
357  technology_nodeRef f_unit_alias = HLS_D->get_technology_manager()->get_fu(component_name, library);
358  THROW_ASSERT(f_unit_alias, "Library miss component: " + component_name);
359  auto* fu_alias = GetPointer<functional_unit>(f_unit_alias);
360  technology_nodeRef op_alias_node = fu_alias->get_operation(operation_name);
361  operation* op_alias = op_alias_node ? GetPointer<operation>(op_alias_node) :
362  GetPointer<operation>(fu_alias->get_operations().front());
363  const auto ret = time_m_stage_period(op_alias);
364  return ret;
365  }
366  else
367  {
368  return time_m_stage_period(GetPointer<operation>(node_op));
369  }
370  }();
371  if(stage_time < clock_budget && stage_time > 0)
372  {
373  return (n_cycles - 1) * clock_budget + stage_time;
374  }
375  else
376  {
377  double exec_time = get_execution_time_dsp_modified(fu_name, node_op);
378  if(exec_time > (n_cycles - 1) * clock_budget && exec_time < n_cycles * clock_budget)
379  {
380  return exec_time;
381  }
382  else
383  {
384  return n_cycles * clock_budget;
385  }
386  }
387  }
390  if(GetPointer<functional_unit>(list_of_FU[fu_name])->component_timing_alias != "")
391  {
393  std::string component_name = GetPointer<functional_unit>(list_of_FU[fu_name])->component_timing_alias;
394  std::string library = HLS_D->get_technology_manager()->get_library(component_name);
395  technology_nodeRef f_unit_alias = HLS_D->get_technology_manager()->get_fu(component_name, library);
396  THROW_ASSERT(f_unit_alias, "Library miss component: " + component_name);
397  auto* fu_alias = GetPointer<functional_unit>(f_unit_alias);
400  technology_nodeRef op_alias_node = fu_alias->get_operation(operation_name);
401  op_alias_node = op_alias_node ? op_alias_node : fu_alias->get_operations().front();
402  return get_execution_time_dsp_modified(fu_name, op_alias_node);
403  }
404 
405  return get_execution_time_dsp_modified(fu_name, node_op);
406 }
407 
409  Allocation_MinMax allocation_min_max,
411 {
412  unsigned int fu_name;
413  bool flag;
414  double res = get_attribute_of_fu_per_op(v, g, allocation_min_max, target, fu_name, flag);
415  THROW_ASSERT(flag, "something wrong happened");
416  return res;
417 }
418 
420  Allocation_MinMax allocation_min_max,
421  AllocationInformation::op_target target, unsigned int& fu_name,
422  bool& flag, const updatecopy_HLS_constraints_functor* CF) const
423 {
424  const unsigned int node_id = g->CGetOpNodeInfo(v)->GetNodeId();
425  const auto node_operation = [&]() -> std::string {
426  if(node_id == ENTRY_ID)
427  {
428  return "Entry";
429  }
430  if(node_id == EXIT_ID)
431  {
432  return "Exit";
433  }
434  return GetPointer<const gimple_node>(TreeM->CGetTreeNode(node_id))->operation;
435  }();
436  const CustomOrderedSet<unsigned int>& fu_set =
437  node_id_to_fus.find(std::pair<unsigned int, std::string>(node_id, node_operation))->second;
438 
439  std::string op_name = tree_helper::NormalizeTypename(g->CGetOpNodeInfo(v)->GetOperation());
440  const CustomOrderedSet<unsigned int>::const_iterator f_end = fu_set.end();
441  auto f_i = fu_set.begin();
442  flag = false;
443  while(CF && f_i != f_end &&
444  ((*CF)(*f_i) <= 0 || (binding.find(node_id) != binding.end() && binding.find(node_id)->second.second != *f_i)))
445  {
446  ++f_i;
447  }
448  if(f_i == f_end)
449  {
450  return -1.0;
451  }
452  flag = true;
453 
454  switch(target)
455  {
456  case initiation_time:
457  {
458  ControlStep temp(0u);
459  fu_name = *f_i;
460  if(!has_to_be_synthetized(fu_name))
461  {
462  return 1.0;
463  }
464 
465  THROW_ASSERT(
466  GetPointer<operation>(GetPointer<functional_unit>(list_of_FU[fu_name])->get_operation(op_name))->time_m,
467  "Timing information not specified for operation " + op_name + " on unit " +
468  id_to_fu_names.find(fu_name)->second.first);
469  auto int_value =
470  GetPointer<operation>(GetPointer<functional_unit>(list_of_FU[fu_name])->get_operation(op_name))
471  ->time_m->get_initiation_time();
472 
473  if(binding.find(node_id) != binding.end() && binding.find(node_id)->second.second == fu_name)
474  {
475  return from_strongtype_cast<double>(int_value);
476  }
477  ++f_i;
478 
479  for(; f_i != f_end; ++f_i)
480  {
481  if(CF && (*CF)(*f_i) <= 0)
482  {
483  continue;
484  }
485  switch(allocation_min_max)
486  {
488  THROW_ASSERT(
489  GetPointer<operation>(GetPointer<functional_unit>(list_of_FU[*f_i])->get_operation(op_name))
490  ->time_m,
491  "Timing information not specified for operation " + op_name + " on unit " +
492  id_to_fu_names.find(*f_i)->second.first);
493  temp = std::max(int_value, GetPointer<operation>(
494  GetPointer<functional_unit>(list_of_FU[*f_i])->get_operation(op_name))
495  ->time_m->get_initiation_time());
496  break;
498  THROW_ASSERT(
499  GetPointer<operation>(GetPointer<functional_unit>(list_of_FU[*f_i])->get_operation(op_name))
500  ->time_m,
501  "Timing information not specified for operation " + op_name + " on unit " +
502  id_to_fu_names.find(*f_i)->second.first);
503  temp = std::min(int_value, GetPointer<operation>(
504  GetPointer<functional_unit>(list_of_FU[*f_i])->get_operation(op_name))
505  ->time_m->get_initiation_time());
506  break;
507  default:
508  temp = ControlStep(0u);
509  THROW_ERROR(std::string("Not supported AllocationInformation::op_performed"));
510  break;
511  }
512  if(temp != int_value)
513  {
514  fu_name = *f_i;
515  int_value = temp;
516  }
517  }
518  return from_strongtype_cast<double>(int_value);
519  }
520  case execution_time:
521  {
522  double temp;
523  fu_name = *f_i;
524  if(!has_to_be_synthetized(fu_name))
525  {
526  return 0.0;
527  }
528  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Get Execution time " + GET_NAME(g, v));
529  THROW_ASSERT(GetPointer<functional_unit>(list_of_FU[fu_name]), "");
530  THROW_ASSERT(GetPointer<operation>(GetPointer<functional_unit>(list_of_FU[fu_name])->get_operation(op_name)),
531  op_name + " not provided by " + list_of_FU[fu_name]->get_name());
532  THROW_ASSERT(
533  GetPointer<operation>(GetPointer<functional_unit>(list_of_FU[fu_name])->get_operation(op_name))->time_m,
534  "Timing information not specified for operation " + op_name + " on unit " +
535  id_to_fu_names.find(fu_name)->second.first);
536  double double_value = get_execution_time_dsp_modified(
537  fu_name, GetPointer<functional_unit>(list_of_FU[fu_name])->get_operation(op_name));
538  if(binding.find(node_id) != binding.end() && binding.find(node_id)->second.second == fu_name)
539  {
540  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Got Execution time: " + STR(double_value));
541  return double_value;
542  }
543  ++f_i;
544  for(; f_i != f_end; ++f_i)
545  {
546  if(CF && (*CF)(*f_i) <= 0)
547  {
548  continue;
549  }
550  switch(allocation_min_max)
551  {
553  THROW_ASSERT(
554  GetPointer<operation>(GetPointer<functional_unit>(list_of_FU[*f_i])->get_operation(op_name))
555  ->time_m,
556  "Timing information not specified for operation " + op_name + " on unit " +
557  id_to_fu_names.find(*f_i)->second.first);
558  temp = std::max(double_value,
560  fu_name, GetPointer<functional_unit>(list_of_FU[*f_i])->get_operation(op_name)));
561  break;
563  THROW_ASSERT(
564  GetPointer<operation>(GetPointer<functional_unit>(list_of_FU[*f_i])->get_operation(op_name))
565  ->time_m,
566  "Timing information not specified for operation " + op_name + " on unit " +
567  id_to_fu_names.find(*f_i)->second.first);
568  temp = std::min(double_value,
570  fu_name, GetPointer<functional_unit>(list_of_FU[*f_i])->get_operation(op_name)));
571  break;
572  default:
573  temp = 0;
574  THROW_ERROR(std::string("Not supported AllocationInformation::op_performed"));
575  break;
576  }
577  if(temp != double_value)
578  {
579  fu_name = *f_i;
580  double_value = temp;
581  }
582  }
583  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Got Execution time: " + STR(double_value));
584  return double_value;
585  }
586  case(power_consumption):
587  default:
588  THROW_ERROR(std::string("Not supported AllocationInformation::op_target"));
589  break;
590  }
591  return -1.0;
592 }
593 
595 {
596  const auto node_id = op_graph->CGetOpNodeInfo(v)->GetNodeId();
597  if(node_id == ENTRY_ID)
598  {
599  return INFINITE_UINT;
600  }
601  if(node_id == EXIT_ID)
602  {
603  return INFINITE_UINT;
604  }
605  const auto operation = GetPointer<const gimple_node>(TreeM->CGetTreeNode(node_id))->operation;
606 
607  const CustomOrderedSet<unsigned int>& fu_set =
608  node_id_to_fus.find(std::pair<unsigned int, std::string>(node_id, operation))->second;
609 
610  unsigned int min_num_res = INFINITE_UINT;
611  const CustomOrderedSet<unsigned int>::const_iterator f_end = fu_set.end();
612 
613  for(auto f_i = fu_set.begin(); f_i != f_end; ++f_i)
614  {
615  unsigned int num_res = tech_constraints[*f_i];
616  THROW_ASSERT(num_res != 0, "something wrong happened");
617  min_num_res = min_num_res > num_res ? num_res : min_num_res;
618  }
619  return min_num_res;
620 }
621 
623 {
624  return HLS_D->get_technology_manager()->CGetSetupHoldTime() * time_multiplier * setup_multiplier;
625 }
626 
628 {
629  technology_nodeRef current_fu = get_fu(fu_type);
630  std::string memory_ctrl_type = GetPointer<functional_unit>(current_fu)->memory_ctrl_type;
631  return memory_ctrl_type != "" && memory_ctrl_type != MEMORY_CTRL_TYPE_PROXY &&
632  memory_ctrl_type != MEMORY_CTRL_TYPE_PROXYN && memory_ctrl_type != MEMORY_CTRL_TYPE_DPROXY &&
633  memory_ctrl_type != MEMORY_CTRL_TYPE_DPROXYN && memory_ctrl_type != MEMORY_CTRL_TYPE_SPROXY &&
634  memory_ctrl_type != MEMORY_CTRL_TYPE_SPROXYN;
635 }
636 
637 double AllocationInformation::get_worst_execution_time(const unsigned int fu_name) const
638 {
639  if(!has_to_be_synthetized(fu_name))
640  {
641  return 0.0;
642  }
643  const functional_unit::operation_vec node_ops = GetPointer<functional_unit>(list_of_FU[fu_name])->get_operations();
644  double max_value = 0.0;
645  auto no_it_end = node_ops.end();
646  for(auto no_it = node_ops.begin(); no_it != no_it_end; ++no_it)
647  {
648  max_value = std::max(max_value, get_execution_time_dsp_modified(fu_name, *no_it));
649  }
650  return max_value;
651 }
652 
653 double AllocationInformation::get_area(const unsigned int fu_name) const
654 {
655  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
656  if(!has_to_be_synthetized(fu_name))
657  {
658  return 0.0;
659  }
660  area_infoRef a_m = GetPointer<functional_unit>(list_of_FU[fu_name])->area_m;
661  THROW_ASSERT(a_m, "Area information not specified for unit " + id_to_fu_names.find(fu_name)->second.first);
662  auto area = a_m->get_resource_value(area_info::SLICE_LUTS);
663  if(area == 0.0)
664  {
665  area = a_m->get_area_value();
666  }
667  return area;
668 }
669 
670 double AllocationInformation::GetStatementArea(const unsigned int statement_index) const
671 {
672  if(CanImplementSetNotEmpty(statement_index))
673  {
674  return get_area(GetFuType(statement_index));
675  }
676 
677  const auto stmt = TreeM->CGetTreeNode(statement_index);
678  const auto stmt_kind = stmt->get_kind();
679  if(stmt_kind == gimple_assign_K)
680  {
681  const auto ga = GetPointerS<const gimple_assign>(stmt);
682  const auto op1_kind = GET_CONST_NODE(ga->op1)->get_kind();
683  if(op1_kind == ssa_name_K || op1_kind == integer_cst_K || op1_kind == convert_expr_K || op1_kind == nop_expr_K ||
684  op1_kind == bit_ior_concat_expr_K || op1_kind == extract_bit_expr_K)
685  {
686  return 0.0;
687  }
688  else if((op1_kind == rshift_expr_K || op1_kind == lshift_expr_K) &&
689  GET_CONST_NODE(GetPointerS<const binary_expr>(GET_CONST_NODE(ga->op1))->op1)->get_kind() == integer_cst_K)
690  {
691  return 0.0;
692  }
693  else if(op1_kind == cond_expr_K || op1_kind == vec_cond_expr_K)
694  {
695  THROW_ASSERT(tree_helper::Size(GetPointerS<const cond_expr>(GET_NODE(ga->op1))->op0) == 1,
696  "Cond expr not allocated " + ga->op1->ToString());
698  const auto data_bitsize = tree_helper::Size(ga->op0);
699  const auto fu_prec = resize_1_8_pow2(data_bitsize);
700  const auto op_area = mux_area_unit_raw(fu_prec);
701  return op_area;
702  }
703 
704  const auto data_bitsize = tree_helper::Size(ga->op0);
705  const auto fu_prec = resize_1_8_pow2(data_bitsize);
706  std::string fu_name;
707  if(op1_kind == widen_mult_expr_K || op1_kind == mult_expr_K)
708  {
709  const auto in_prec = op1_kind == mult_expr_K ? fu_prec : (fu_prec / 2);
710  fu_name =
711  tree_node::GetString(op1_kind) + "_FU_" + STR(in_prec) + "_" + STR(in_prec) + "_" + STR(fu_prec) + "_0";
712  }
713  else if(op1_kind == lut_expr_K)
714  {
715  fu_name = tree_node::GetString(op1_kind) + "_FU";
716  }
717  else if(GetPointer<const unary_expr>(GET_CONST_NODE(ga->op1)))
718  {
719  fu_name = tree_node::GetString(op1_kind) + "_FU_" + STR(fu_prec) + "_" + STR(fu_prec);
720  }
721  else if(GetPointer<const binary_expr>(GET_CONST_NODE(ga->op1)))
722  {
723  fu_name = tree_node::GetString(op1_kind) + "_FU_" + STR(fu_prec) + "_" + STR(fu_prec) + "_" + STR(fu_prec);
724  }
725  else if(GetPointer<const ternary_expr>(GET_CONST_NODE(ga->op1)))
726  {
727  fu_name = tree_node::GetString(op1_kind) + "_FU_" + STR(fu_prec) + "_" + STR(fu_prec) + "_" + STR(fu_prec) +
728  "_" + STR(fu_prec);
729  }
730  else
731  {
732  THROW_UNREACHABLE("Unhandled operation (" + GET_CONST_NODE(ga->op1)->get_kind_text() + ")" + STR(stmt));
733  }
734  const auto new_stmt_temp = HLS_D->get_technology_manager()->get_fu(fu_name, LIBRARY_STD_FU);
735  THROW_ASSERT(new_stmt_temp, "Functional unit '" + fu_name + "' not found");
736  const auto new_stmt_fu = GetPointerS<const functional_unit>(new_stmt_temp);
737  return new_stmt_fu->area_m->get_area_value();
738  }
739  else if(stmt_kind == gimple_multi_way_if_K || stmt_kind == gimple_cond_K || stmt_kind == gimple_return_K)
740  {
741  return 0.0;
742  }
743  THROW_UNREACHABLE(STR(statement_index) + " - " + STR(stmt));
744  return 0.0;
745 }
746 
747 double AllocationInformation::get_DSPs(const unsigned int fu_name) const
748 {
749  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
750  if(!has_to_be_synthetized(fu_name))
751  {
752  return 0.0;
753  }
754  area_infoRef a_m = GetPointer<functional_unit>(list_of_FU[fu_name])->area_m;
755  THROW_ASSERT(a_m, "Area information not specified for unit " + id_to_fu_names.find(fu_name)->second.first);
756  if(a_m)
757  {
758  return a_m->get_resource_value(area_info::DSP);
759  }
760  else
761  {
762  return 0;
763  }
764 }
765 
766 ControlStep AllocationInformation::get_initiation_time(const unsigned int fu_name, const vertex v) const
767 {
768  return get_initiation_time(fu_name, op_graph->CGetOpNodeInfo(v)->GetNodeId());
769 }
770 
771 ControlStep AllocationInformation::get_initiation_time(const unsigned int fu_name,
772  const unsigned int statement_index) const
773 {
774  if(statement_index == ENTRY_ID || statement_index == EXIT_ID)
775  {
776  return ControlStep(0u);
777  }
778  const auto operation_name = GetPointer<const gimple_node>(TreeM->CGetTreeNode(statement_index))->operation;
779  THROW_ASSERT(can_implement_set(statement_index).find(fu_name) != can_implement_set(statement_index).end(),
780  "This function (" + get_string_name(fu_name) + ") cannot implement the operation " + operation_name);
781  if(!has_to_be_synthetized(fu_name))
782  {
783  return ControlStep(0u);
784  }
785  technology_nodeRef node_op =
786  GetPointer<functional_unit>(list_of_FU[fu_name])->get_operation(tree_helper::NormalizeTypename(operation_name));
787  THROW_ASSERT(GetPointer<operation>(node_op)->time_m,
788  "Timing information not specified for unit " + id_to_fu_names.find(fu_name)->second.first);
789  return GetPointer<operation>(node_op)->time_m->get_initiation_time();
790 }
791 
792 bool AllocationInformation::is_operation_bounded(const OpGraphConstRef g, const vertex& op, unsigned int fu_type) const
793 {
794  const technology_nodeRef node = get_fu(fu_type);
795  std::string op_string = tree_helper::NormalizeTypename(g->CGetOpNodeInfo(op)->GetOperation());
796  const functional_unit* fu = GetPointer<functional_unit>(node);
797  const technology_nodeRef op_node = fu->get_operation(op_string);
798  THROW_ASSERT(GetPointer<operation>(op_node), "Op node is not an operation");
799  return GetPointer<operation>(op_node)->is_bounded();
800 }
801 
802 bool AllocationInformation::is_operation_bounded(const unsigned int index, unsigned int fu_type) const
803 {
804  const technology_nodeRef node = get_fu(fu_type);
805  std::string op_string =
806  tree_helper::NormalizeTypename(GetPointer<const gimple_node>(TreeM->CGetTreeNode(index))->operation);
807  const functional_unit* fu = GetPointer<functional_unit>(node);
808  const technology_nodeRef op_node = fu->get_operation(op_string);
809  THROW_ASSERT(op_node, get_fu_name(fu_type).first + " cannot execute " + op_string);
810  THROW_ASSERT(GetPointer<operation>(op_node), "Op node is not an operation: " + op_string);
811  return GetPointer<operation>(op_node)->is_bounded();
812 }
813 
815  unsigned int fu_type) const
816 {
817  const technology_nodeRef node = get_fu(fu_type);
818  std::string op_string = tree_helper::NormalizeTypename(g->CGetOpNodeInfo(op)->GetOperation());
819  const functional_unit* fu = GetPointer<functional_unit>(node);
820  const technology_nodeRef op_node = fu->get_operation(op_string);
821  THROW_ASSERT(GetPointer<operation>(op_node), "Op node is not an operation");
822  return GetPointer<operation>(op_node)->is_primary_inputs_registered();
823 }
824 
825 bool AllocationInformation::is_operation_PI_registered(const unsigned int index, unsigned int fu_type) const
826 {
827  const technology_nodeRef node = get_fu(fu_type);
828  std::string op_string =
829  tree_helper::NormalizeTypename(GetPointer<const gimple_node>(TreeM->CGetTreeNode(index))->operation);
830  const functional_unit* fu = GetPointer<functional_unit>(node);
831  const technology_nodeRef op_node = fu->get_operation(op_string);
832  THROW_ASSERT(GetPointer<operation>(op_node), "Op node is not an operation");
833  return GetPointer<operation>(op_node)->is_primary_inputs_registered();
834 }
835 
837 {
838  if(CanImplementSetNotEmpty(index))
839  {
840  return is_operation_PI_registered(index, GetFuType(index));
841  }
842  return false;
843 }
844 
846 {
847  if(CanImplementSetNotEmpty(index))
848  {
849  return is_operation_bounded(index, GetFuType(index));
850  }
851  auto tn = TreeM->CGetTreeNode(index);
852  const auto ga = GetPointer<const gimple_assign>(tn);
853 
855  if(ga)
856  {
857  const auto right_kind = GET_CONST_NODE(ga->op1)->get_kind();
859  // BEAWARE: when adding operations here, check they are correctly handled by GetTimeLatency and GetCycleLatency
860  THROW_ASSERT(GetPointer<const cst_node>(GET_CONST_NODE(ga->op1)) || right_kind == ssa_name_K ||
861  right_kind == cond_expr_K || right_kind == vec_cond_expr_K || right_kind == convert_expr_K ||
862  right_kind == nop_expr_K || right_kind == bit_ior_concat_expr_K ||
863  right_kind == extract_bit_expr_K || right_kind == lut_expr_K || right_kind == truth_not_expr_K ||
864  right_kind == bit_not_expr_K || right_kind == negate_expr_K || right_kind == bit_xor_expr_K ||
865  right_kind == bit_ior_expr_K || right_kind == bit_and_expr_K || right_kind == truth_and_expr_K ||
866  right_kind == truth_or_expr_K || right_kind == truth_xor_expr_K || right_kind == lshift_expr_K ||
867  right_kind == rshift_expr_K || right_kind == widen_mult_expr_K || right_kind == mult_expr_K ||
868  right_kind == plus_expr_K || right_kind == minus_expr_K || right_kind == ternary_plus_expr_K ||
869  right_kind == eq_expr_K || right_kind == ne_expr_K || right_kind == lt_expr_K ||
870  right_kind == le_expr_K || right_kind == gt_expr_K || right_kind == ge_expr_K ||
871  right_kind == ternary_mp_expr_K || right_kind == ternary_pm_expr_K ||
872  right_kind == ternary_mm_expr_K,
873  "Unexpected right part: " + tree_node::GetString(right_kind));
874  return true;
875  }
876  if(GetPointer<const gimple_nop>(tn))
877  {
878  return true;
879  }
880  if(GetPointer<const gimple_phi>(tn))
881  {
882  return true;
883  }
884  THROW_ERROR("Unexpected operation in AllocationInformation::is_operation_bounded: " + tn->get_kind_text());
885  return false;
886 }
887 
888 bool AllocationInformation::is_dual_port_memory(unsigned int fu_type) const
889 {
890  technology_nodeRef current_fu = get_fu(fu_type);
891  std::string memory_type = GetPointer<functional_unit>(current_fu)->memory_type;
892  std::string memory_ctrl_type = GetPointer<functional_unit>(current_fu)->memory_ctrl_type;
893  return memory_type == "ASYNCHRONOUS" || memory_type == "SYNCHRONOUS_SDS" ||
894  memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXY || memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXYN ||
895  memory_ctrl_type == MEMORY_CTRL_TYPE_SPROXY || memory_ctrl_type == MEMORY_CTRL_TYPE_SPROXYN;
896 }
897 
899 {
900  technology_nodeRef current_fu = get_fu(fu_type);
901  std::string memory_type = GetPointer<functional_unit>(current_fu)->memory_type;
902  std::string memory_ctrl_type = GetPointer<functional_unit>(current_fu)->memory_ctrl_type;
903  return memory_type != "" || memory_ctrl_type == MEMORY_CTRL_TYPE_PROXY ||
904  memory_ctrl_type == MEMORY_CTRL_TYPE_PROXYN || memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXY ||
905  memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXYN || memory_ctrl_type == MEMORY_CTRL_TYPE_SPROXY ||
906  memory_ctrl_type == MEMORY_CTRL_TYPE_SPROXYN;
907 }
908 
910 {
911  technology_nodeRef current_fu = get_fu(fu_type);
912  std::string memory_ctrl_type = GetPointer<functional_unit>(current_fu)->memory_ctrl_type;
913  return memory_ctrl_type == MEMORY_CTRL_TYPE_PROXY || memory_ctrl_type == MEMORY_CTRL_TYPE_PROXYN ||
914  memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXY || memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXYN ||
915  memory_ctrl_type == MEMORY_CTRL_TYPE_SPROXY || memory_ctrl_type == MEMORY_CTRL_TYPE_SPROXYN;
916 }
917 
918 bool AllocationInformation::is_memory_unit(const unsigned int fu_name) const
919 {
920  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
921  return memory_units.find(fu_name) != memory_units.end();
922 }
923 
924 bool AllocationInformation::is_proxy_unit(const unsigned int fu_name) const
925 {
926  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
927  return is_proxy_function_unit(fu_name) || is_proxy_wrapped_unit(fu_name);
928 }
929 
930 bool AllocationInformation::is_proxy_function_unit(const unsigned int fu_name) const
931 {
932  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
933  return proxy_function_units.find(fu_name) != proxy_function_units.end();
934 }
935 
936 bool AllocationInformation::is_proxy_wrapped_unit(const unsigned int fu_name) const
937 {
938  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
939  return proxy_wrapped_units.find(fu_name) != proxy_wrapped_units.end();
940 }
941 
942 bool AllocationInformation::is_vertex_bounded(const unsigned int fu_name) const
943 {
944  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
945  return is_vertex_bounded_rel.find(fu_name) != is_vertex_bounded_rel.end();
946 }
947 
948 bool AllocationInformation::is_vertex_bounded_with(const vertex v, unsigned int& fu_name) const
949 {
950  return is_vertex_bounded_with(op_graph->CGetOpNodeInfo(v)->GetNodeId(), fu_name);
951 }
952 
953 bool AllocationInformation::is_vertex_bounded_with(const unsigned int v, unsigned int& fu_name) const
954 {
955  if(binding.find(v) == binding.end())
956  {
957  return false;
958  }
959  else
960  {
963  if(v != ENTRY_ID && v != EXIT_ID &&
964  GetPointer<const gimple_node>(TreeM->CGetTreeNode(v))->operation != binding.find(v)->second.first)
965  {
966  return false;
967  }
968  fu_name = binding.find(v)->second.second;
969  return true;
970  }
971 }
972 
973 bool AllocationInformation::is_artificial_fu(const unsigned int fu_name) const
974 {
975  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
976  std::string fu_string_name = list_of_FU[fu_name]->get_name();
977  if(fu_string_name == ASSIGN_UNSIGNED_STD || fu_string_name == ASSIGN_SIGNED_STD ||
978  fu_string_name == ASSIGN_REAL_STD || !has_to_be_synthetized(fu_name))
979  {
980  return true;
981  }
982  else
983  {
984  return false;
985  }
986 }
987 
988 unsigned int AllocationInformation::get_memory_var(const unsigned int fu_name) const
989 {
990  THROW_ASSERT(is_memory_unit(fu_name), "functional unit id not meaningful");
991  return memory_units.find(fu_name)->second;
992 }
993 
994 std::map<unsigned int, unsigned int> AllocationInformation::get_memory_units() const
995 {
996  return memory_units;
997 }
998 
999 const std::map<unsigned int, unsigned int>& AllocationInformation::get_proxy_memory_units() const
1000 {
1001  return proxy_memory_units;
1002 }
1003 
1004 unsigned int AllocationInformation::get_proxy_memory_var(const unsigned int fu_name) const
1005 {
1006  THROW_ASSERT(proxy_memory_units.find(fu_name) != proxy_memory_units.end(), "functional unit id not meaningful");
1007  return proxy_memory_units.find(fu_name)->second;
1008 }
1009 
1010 const std::map<unsigned int, std::string>& AllocationInformation::get_proxy_function_units() const
1011 {
1012  return proxy_function_units;
1013 }
1014 
1015 const std::map<unsigned int, std::string>& AllocationInformation::get_proxy_wrapped_units() const
1016 {
1017  return proxy_wrapped_units;
1018 }
1019 
1020 bool AllocationInformation::has_to_be_synthetized(const unsigned int fu_name) const
1021 {
1022  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
1023  std::string fu_string_name = list_of_FU[fu_name]->get_name();
1024  if(fu_string_name == GIMPLE_RETURN_STD || fu_string_name == ENTRY_STD || fu_string_name == EXIT_STD ||
1025  fu_string_name == NOP_STD || fu_string_name == GIMPLE_PHI_STD || fu_string_name == GIMPLE_ASM_STD ||
1026  fu_string_name == GIMPLE_LABEL_STD || fu_string_name == GIMPLE_GOTO_STD || fu_string_name == GIMPLE_NOP_STD ||
1027  fu_string_name == GIMPLE_PRAGMA_STD)
1028  {
1029  return false;
1030  }
1031  else
1032  {
1033  return true;
1034  }
1035 }
1036 
1037 double AllocationInformation::get_stage_period(const unsigned int fu_name, const vertex v,
1038  const OpGraphConstRef g) const
1039 {
1040  return get_stage_period(fu_name, g->CGetOpNodeInfo(v)->GetNodeId());
1041 }
1042 
1043 double AllocationInformation::get_stage_period(const unsigned int fu_name, const unsigned int v) const
1044 {
1045  if(v == ENTRY_ID || v == EXIT_ID)
1046  {
1047  return 0.0;
1048  }
1049  const std::string operation_t = GetPointer<const gimple_node>(TreeM->CGetTreeNode(v))->operation;
1050  THROW_ASSERT(can_implement_set(v).find(fu_name) != can_implement_set(v).end(),
1051  "This function (" + get_string_name(fu_name) + ") cannot implement the operation " +
1052  tree_helper::NormalizeTypename(operation_t));
1053  if(!has_to_be_synthetized(fu_name))
1054  {
1055  return 0.0;
1056  }
1057  technology_nodeRef node_op =
1058  GetPointer<functional_unit>(list_of_FU[fu_name])->get_operation(tree_helper::NormalizeTypename(operation_t));
1059  THROW_ASSERT(GetPointer<operation>(node_op)->time_m,
1060  "Timing information not specified for unit " + id_to_fu_names.find(fu_name)->second.first);
1063  if(GetPointer<functional_unit>(list_of_FU[fu_name])->component_timing_alias != "")
1064  {
1065  std::string component_name = GetPointer<functional_unit>(list_of_FU[fu_name])->component_timing_alias;
1066  std::string library = HLS_D->get_technology_manager()->get_library(component_name);
1067  technology_nodeRef f_unit_alias = HLS_D->get_technology_manager()->get_fu(component_name, library);
1068  THROW_ASSERT(f_unit_alias, "Library miss component: " + component_name);
1069  auto* fu_alias = GetPointer<functional_unit>(f_unit_alias);
1070  technology_nodeRef op_alias_node = fu_alias->get_operation(operation_t);
1071  operation* op_alias = op_alias_node ? GetPointer<operation>(op_alias_node) :
1072  GetPointer<operation>(fu_alias->get_operations().front());
1073  return time_m_stage_period(op_alias);
1074  }
1075  else
1076  {
1077  THROW_ASSERT(GetPointer<operation>(node_op), "");
1078  return time_m_stage_period(GetPointer<operation>(node_op));
1079  }
1080 }
1081 
1082 double AllocationInformation::estimate_mux_time(unsigned int fu_name) const
1083 {
1084  auto fu_prec = get_prec(fu_name);
1085  fu_prec = resize_1_8_pow2(fu_prec);
1086  return mux_time_unit(fu_prec);
1087 }
1088 
1089 double AllocationInformation::estimate_muxNto1_delay(unsigned long long fu_prec, unsigned int mux_ins) const
1090 {
1091  if(mux_ins < 2)
1092  {
1093  return 0;
1094  }
1095  fu_prec = resize_1_8_pow2(fu_prec);
1096  if(mux_ins > MAX_MUX_N_INPUTS)
1097  {
1098  return HLS_C->get_clock_period();
1099  }
1100  if(fu_prec > 128)
1101  {
1102  fu_prec = 128;
1103  }
1104  THROW_ASSERT(mux_timing_db.find(fu_prec) != mux_timing_db.end(),
1105  STR(fu_prec) + " not found in mux database of " + STR(mux_timing_db.size()) + " elements");
1106  while(mux_timing_db.find(fu_prec)->second.find(mux_ins) == mux_timing_db.find(fu_prec)->second.end() &&
1107  mux_ins <= MAX_MUX_N_INPUTS)
1108  {
1109  ++mux_ins;
1110  }
1111  THROW_ASSERT(mux_timing_db.find(fu_prec)->second.find(mux_ins) != mux_timing_db.find(fu_prec)->second.end(),
1112  "fu_prec:" + STR(fu_prec) + " mux_ins: " + STR(mux_ins));
1113  double ret = mux_timing_db.at(fu_prec).at(mux_ins) - get_setup_hold_time();
1114  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---delay of MUX with " + STR(mux_ins) + " inputs and with
1115  // " + STR(fu_prec) + " bits: " + STR(ret));
1116  return ret;
1117 }
1118 
1119 double AllocationInformation::estimate_muxNto1_area(unsigned long long fu_prec, unsigned int mux_ins) const
1120 {
1121  if(mux_ins < 2)
1122  {
1123  return 0;
1124  }
1125  fu_prec = resize_1_8_pow2(fu_prec);
1126  if(mux_ins > MAX_MUX_N_INPUTS)
1127  {
1129  }
1130  while(mux_area_db.find(fu_prec)->second.find(mux_ins) == mux_area_db.find(fu_prec)->second.end() &&
1131  mux_ins <= MAX_MUX_N_INPUTS)
1132  {
1133  ++mux_ins;
1134  }
1135  double ret = mux_area_db.at(fu_prec).at(mux_ins);
1136  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---area of MUX with " + STR(mux_ins) + " inputs and with "
1137  // + STR(fu_prec) + " bits: " + STR(ret));
1138  THROW_ASSERT(ret != 0.0, "unexpected condition");
1139  return ret;
1140 }
1141 
1142 unsigned int AllocationInformation::get_cycles(const unsigned int fu_name, const vertex v,
1143  const OpGraphConstRef g) const
1144 {
1145  return get_cycles(fu_name, g->CGetOpNodeInfo(v)->GetNodeId());
1146 }
1147 
1148 unsigned int AllocationInformation::get_cycles(const unsigned int fu_name, const unsigned int v) const
1149 {
1150  if(v == ENTRY_ID || v == EXIT_ID)
1151  {
1152  return 0;
1153  }
1154  const std::string operation_t = GetPointer<const gimple_node>(TreeM->CGetTreeNode(v))->operation;
1155  THROW_ASSERT(can_implement_set(v).find(fu_name) != can_implement_set(v).end(),
1156  "This function (" + get_string_name(fu_name) + ") cannot implement the operation " +
1157  tree_helper::NormalizeTypename(operation_t));
1158  if(!has_to_be_synthetized(fu_name))
1159  {
1160  return 0;
1161  }
1162  technology_nodeRef node_op = GetPointer<functional_unit>(list_of_FU[fu_name])->get_operation(operation_t);
1163  THROW_ASSERT(GetPointer<operation>(node_op), id_to_fu_names.at(fu_name).first);
1164  THROW_ASSERT(GetPointer<operation>(node_op)->time_m, "Timing information not specified for operation " +
1165  node_op->get_name() + " on unit " +
1166  id_to_fu_names.find(fu_name)->second.first);
1167  return GetPointer<operation>(node_op)->time_m->get_cycles();
1168 }
1169 
1171 {
1172  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id " + STR(fu_name) + " is not meaningful");
1173  return list_of_FU[fu_name];
1174 }
1175 
1176 unsigned int AllocationInformation::get_number_channels(unsigned int fu_name) const
1177 {
1178  if(nports_map.find(fu_name) == nports_map.end())
1179  {
1180  return 0;
1181  }
1182  else
1183  {
1184  return nports_map.find(fu_name)->second;
1185  }
1186 }
1187 
1189 std::string AllocationInformation::get_string_name(unsigned int fu_name) const
1190 {
1191  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
1192  return list_of_FU[fu_name]->get_name() + "_" + STR(fu_name);
1193 }
1194 
1195 bool AllocationInformation::can_implement(const unsigned int fu_id, const vertex v) const
1196 {
1197  return can_implement_set(v).find(fu_id) != can_implement_set(v).end();
1198 }
1199 
1200 bool AllocationInformation::is_read_cond(const unsigned int fu_name) const
1201 {
1202  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
1203  return list_of_FU[fu_name]->get_name() == READ_COND_STD;
1204 }
1205 
1206 bool AllocationInformation::is_assign(const unsigned int fu_name) const
1207 {
1208  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
1209  return list_of_FU[fu_name]->get_name() == ASSIGN_UNSIGNED_STD ||
1210  list_of_FU[fu_name]->get_name() == ASSIGN_SIGNED_STD || list_of_FU[fu_name]->get_name() == ASSIGN_REAL_STD;
1211 }
1212 
1213 bool AllocationInformation::is_return(const unsigned int fu_name) const
1214 {
1215  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
1216  return list_of_FU[fu_name]->get_name() == GIMPLE_RETURN_STD;
1217 }
1218 
1220  const technology_nodeRef& node_op) const
1221 {
1222  if(get_DSPs(fu_name) > 0)
1223  {
1224  THROW_ASSERT(GetPointer<operation>(node_op), "");
1225  return DSPs_margin * time_m_execution_time(GetPointer<operation>(node_op));
1226  }
1227  else
1228  {
1229  return time_m_execution_time(GetPointer<operation>(node_op));
1230  }
1231 }
1232 
1234  const technology_nodeRef& node_op) const
1235 {
1236  if(get_DSPs(fu_name) > 0)
1237  {
1238  return DSPs_margin_stage * time_m_stage_period(GetPointer<operation>(node_op));
1239  }
1240  else
1241  {
1242  return time_m_stage_period(GetPointer<operation>(node_op));
1243  }
1244 }
1245 
1246 double AllocationInformation::get_worst_stage_period(const unsigned int fu_name) const
1247 {
1248  if(!has_to_be_synthetized(fu_name))
1249  {
1250  return 0.0;
1251  }
1252  const functional_unit::operation_vec node_ops = GetPointer<functional_unit>(list_of_FU[fu_name])->get_operations();
1253  double max_value = 0.0;
1254  auto no_it_end = node_ops.end();
1255  for(auto no_it = node_ops.begin(); no_it != no_it_end; ++no_it)
1256  {
1257  max_value = std::max(max_value, get_stage_period_dsp_modified(fu_name, *no_it));
1258  }
1259  return max_value;
1260 }
1261 
1262 void AllocationInformation::set_number_channels(unsigned int fu_name, unsigned int n_ports)
1263 {
1264  nports_map[fu_name] = n_ports;
1265 }
1266 
1268 {
1269  const auto node_id = op_graph->CGetOpNodeInfo(v)->GetNodeId();
1270  if(node_id == ENTRY_ID)
1271  {
1272  return INFINITE_UINT;
1273  }
1274  if(node_id == EXIT_ID)
1275  {
1276  return INFINITE_UINT;
1277  }
1278  const auto operation = GetPointer<const gimple_node>(TreeM->CGetTreeNode(node_id))->operation;
1279 
1280  const CustomOrderedSet<unsigned int>& fu_set =
1281  node_id_to_fus.find(std::pair<unsigned int, std::string>(node_id, operation))->second;
1282 
1283  unsigned int tot_num_res = 0;
1284  const CustomOrderedSet<unsigned int>::const_iterator f_end = fu_set.end();
1285 
1286  for(auto f_i = fu_set.begin(); f_i != f_end; ++f_i)
1287  {
1288  auto num_res = tech_constraints[*f_i];
1289  THROW_ASSERT(num_res != 0, "something wrong happened");
1290  if(num_res == INFINITE_UINT)
1291  {
1292  return num_res;
1293  }
1294  else
1295  {
1296  tot_num_res += num_res;
1297  }
1298  }
1299  return tot_num_res;
1300 }
1301 
1302 unsigned int AllocationInformation::max_number_of_operations(unsigned int fu) const
1303 {
1304  THROW_ASSERT(fu < get_number_fu_types(), "functional unit id not meaningful");
1305  THROW_ASSERT(fus_to_node_id.find(fu) != fus_to_node_id.end(),
1306  "no operation can be mapped on the given functional unit");
1307  return static_cast<unsigned int>(fus_to_node_id.find(fu)->second.size());
1308 }
1309 
1311 {
1312  technology_nodeRef current_fu = get_fu(fu_type);
1313  return GetPointer<functional_unit>(current_fu)->memory_type == MEMORY_TYPE_ASYNCHRONOUS ||
1314  GetPointer<functional_unit>(current_fu)->memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXY ||
1315  GetPointer<functional_unit>(current_fu)->memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXYN;
1316 }
1317 
1318 void AllocationInformation::GetNodeTypePrec(const vertex node, const OpGraphConstRef g, node_kind_prec_infoRef info,
1319  HLS_manager::io_binding_type& constant_id, bool is_constrained) const
1320 {
1321  std::vector<HLS_manager::io_binding_type> vars_read = hls_manager->get_required_values(function_index, node);
1322  unsigned int first_valid_id = 0;
1323  unsigned int index = 0;
1324  constant_id = HLS_manager::io_binding_type(0, 0);
1325  if(vars_read.empty())
1326  {
1327  return;
1328  }
1329  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Getting node type precision of " + GET_NAME(g, node));
1330  std::string current_op = tree_helper::NormalizeTypename(g->CGetOpNodeInfo(node)->GetOperation());
1331 
1332  bool is_a_pointer = false;
1334  bool is_second_constant = false;
1335  tree_nodeConstRef formal_parameter_type;
1336  unsigned long long max_size_in = 0;
1337  unsigned long long min_n_elements = 0;
1338  bool is_cond_expr_bool_test = false;
1339  for(auto itr = vars_read.begin(), end = vars_read.end(); itr != end; ++itr, ++index)
1340  {
1341  const auto id = std::get<0>(*itr);
1342  if(id && !first_valid_id)
1343  {
1344  first_valid_id = id;
1345  }
1346  if(current_op == "cond_expr" && id && !tree_helper::IsConstant(TreeM->CGetTreeReindex(id)))
1347  {
1348  if(tree_helper::Size(TreeM->CGetTreeReindex(id)) == 1)
1349  {
1350  is_cond_expr_bool_test = true;
1351  }
1352  }
1353  if((current_op == "cond_expr" || current_op == "vec_cond_expr") && index != 0 && id)
1354  {
1355  first_valid_id = id;
1356  }
1357  if(current_op == "cond_expr" || current_op == "vec_cond_expr")
1358  {
1359  is_second_constant = true;
1360  }
1361  if(id == 0 || ((tree_helper::IsConstant(TreeM->CGetTreeReindex(id)) ||
1362  tree_helper::is_concat_bit_ior_expr(TreeM, g->CGetOpNodeInfo(node)->GetNodeId())) &&
1363  !is_constrained && !is_second_constant && vars_read.size() != 1 && current_op != "mult_expr" &&
1364  current_op != "widen_mult_expr" && current_op != "insertelement_expr" &&
1365  current_op != "extractelement_expr" &&
1366  (index == 1 || current_op != "lut_expr" || current_op != "extract_bit_expr")))
1367  {
1368  info->input_prec.push_back(0);
1369  info->real_input_nelem.push_back(0);
1370  info->base128_input_nelem.push_back(0);
1371  is_second_constant = true;
1372  constant_id = *itr;
1373  if(id)
1374  {
1375  const auto var_node = TreeM->CGetTreeReindex(id);
1376  type = tree_helper::CGetType(var_node);
1377  if(tree_helper::IsVectorType(type))
1378  {
1379  const auto element_type = tree_helper::CGetElements(type);
1380  const auto element_size = tree_helper::Size(element_type);
1381  max_size_in = std::max(max_size_in, element_size);
1382  if(min_n_elements == 0 || ((128 / element_size) < min_n_elements))
1383  {
1384  min_n_elements = 128 / element_size;
1385  }
1386  }
1387  else
1388  {
1389  max_size_in = std::max(max_size_in, tree_helper::Size(var_node));
1390  }
1391  }
1392  }
1393  else
1394  {
1395  const auto var_node = TreeM->CGetTreeReindex(id);
1396  type = tree_helper::CGetType(var_node);
1398  tree_helper::IsUnionType(type) /*|| tree_helper::IsComplexType(type)*/)
1399  {
1400  info->input_prec.push_back(32);
1401  info->real_input_nelem.push_back(0);
1402  info->base128_input_nelem.push_back(0);
1403  }
1404  else
1405  {
1406  const auto& op_node = g->CGetOpNodeInfo(node)->node;
1407  const auto form_par_type = tree_helper::GetFormalIth(op_node, index);
1408  const auto size_tree_var = tree_helper::Size(var_node);
1409  const auto size_form_par = form_par_type ? tree_helper::Size(form_par_type) : 0;
1410  const auto size_value = size_form_par ? size_form_par : size_tree_var;
1411  if(form_par_type && index == 0)
1412  {
1413  formal_parameter_type = form_par_type;
1414  }
1415  if(tree_helper::IsVectorType(type))
1416  {
1417  const auto element_type = tree_helper::CGetElements(type);
1418  const auto vector_size = tree_helper::Size(type);
1419  const auto element_size = tree_helper::Size(element_type);
1420  info->real_input_nelem.push_back(vector_size / element_size);
1421  info->base128_input_nelem.push_back(128 / element_size);
1422  info->input_prec.push_back(element_size);
1424  "---Type is " + STR(type->index) + " " + STR(type) +
1425  " - Number of input elements (base128): " + STR(128 / element_size) +
1426  " - Number of real input elements: " + STR(vector_size / element_size) +
1427  " - Input precision: " + STR(element_size));
1428  }
1429  else
1430  {
1431  info->real_input_nelem.push_back(0);
1432  info->base128_input_nelem.push_back(0);
1433  info->input_prec.push_back(size_value);
1434  }
1435  }
1436  }
1437  }
1438 
1439  THROW_ASSERT(first_valid_id, "Unexpected pattern");
1440  if(formal_parameter_type)
1441  {
1442  type = formal_parameter_type;
1443  is_a_pointer = tree_helper::IsPointerType(type);
1444  }
1445  else
1446  {
1447  type = tree_helper::CGetType(TreeM->CGetTreeReindex(first_valid_id));
1448  is_a_pointer = tree_helper::IsPointerType(type);
1449  }
1450  if(is_a_pointer || tree_helper::IsArrayType(type) || tree_helper::IsStructType(type) ||
1452  {
1453  info->node_kind = "VECTOR_BOOL";
1454  }
1455  else if(tree_helper::IsSignedIntegerType(type))
1456  {
1457  info->node_kind = "INT";
1458  }
1459  else if(tree_helper::IsRealType(type))
1460  {
1461  info->node_kind = "REAL";
1462  }
1463  else if(tree_helper::IsUnsignedIntegerType(type))
1464  {
1465  info->node_kind = "UINT";
1466  }
1467  else if(tree_helper::IsBooleanType(type))
1468  {
1469  info->node_kind = "VECTOR_BOOL";
1470  }
1471  else if(tree_helper::IsVectorType(type))
1472  {
1473  const auto element_type = tree_helper::CGetElements(type);
1474  if(tree_helper::IsSignedIntegerType(element_type))
1475  {
1476  info->node_kind = "VECTOR_INT";
1477  }
1478  else if(tree_helper::IsUnsignedIntegerType(element_type))
1479  {
1480  info->node_kind = "VECTOR_UINT";
1481  }
1482  else if(tree_helper::IsRealType(element_type))
1483  {
1484  info->node_kind = "VECTOR_REAL";
1485  }
1486  }
1487  else
1488  {
1489  THROW_UNREACHABLE("not supported type: " + STR(type->index) + " - " + STR(type));
1490  }
1491 
1492  const auto max_size_in_true =
1493  std::max(max_size_in, *std::max_element(info->input_prec.begin(), info->input_prec.end()));
1494  for(const auto n_elements : info->base128_input_nelem)
1495  {
1496  if(n_elements && (min_n_elements == 0 || (n_elements < min_n_elements)))
1497  {
1498  min_n_elements = n_elements;
1499  }
1500  }
1502  if(is_cond_expr_bool_test)
1503  {
1504  info->is_single_bool_test_cond_expr = true;
1505  }
1506  // if(tree_helper::is_simple_pointer_plus_test(TreeM, g->CGetOpNodeInfo(node)->GetNodeId()))
1507  // info->is_simple_pointer_plus_expr = true;
1508  max_size_in = resize_1_8_pow2(max_size_in_true);
1510  if(current_op == "widen_mult_expr" || current_op == "mult_expr")
1511  {
1512  const auto nodeOutput_id = hls_manager->get_produced_value(function_index, node);
1513  const auto out_node = TreeM->CGetTreeReindex(nodeOutput_id);
1514  type = tree_helper::CGetType(out_node);
1515  if(tree_helper::IsVectorType(type))
1516  {
1517  const auto element_type = tree_helper::CGetElements(type);
1518  const auto element_size = tree_helper::Size(element_type);
1519  const auto output_size = resize_1_8_pow2(tree_helper::Size(out_node));
1520  info->real_output_nelem = output_size / element_size;
1521  info->base128_output_nelem = 128 / element_size;
1522  info->output_prec = element_size;
1523  info->input_prec[0] = max_size_in;
1524  info->input_prec[1] = max_size_in;
1525  }
1526  else
1527  {
1528  THROW_ASSERT(info->input_prec.size() == 2, "unexpected number of inputs");
1529  const auto output_size_true = tree_helper::Size(out_node);
1530  if(output_size_true < info->input_prec[0])
1531  {
1532  info->input_prec[0] = output_size_true;
1533  }
1534  if(output_size_true < info->input_prec[1])
1535  {
1536  info->input_prec[1] = output_size_true;
1537  }
1538  if(info->input_prec[0] > info->input_prec[1])
1539  {
1540  std::swap(info->input_prec[0], info->input_prec[1]);
1541  }
1542  bool resized = false;
1543 
1544  const auto resized_second_index = resize_1_8_pow2(info->input_prec[1]);
1546  for(size_t ind = 0; ind < DSP_y_db.size() && !resized; ind++)
1547  {
1548  const auto y_dsp_size = DSP_y_db[ind];
1549  const auto resized_y_dsp_size = resize_1_8_pow2(y_dsp_size);
1550  if(info->input_prec[1] < y_dsp_size && resized_y_dsp_size == resized_second_index)
1551  {
1552  if(info->input_prec[0] < DSP_x_db[ind])
1553  {
1554  resized = true;
1555  info->input_prec[1] = y_dsp_size;
1556  info->input_prec[0] = DSP_x_db[ind];
1557  }
1558  }
1559  }
1560  if(!resized)
1561  {
1562  max_size_in = std::max(info->input_prec[0], info->input_prec[1]);
1563  max_size_in = resize_1_8_pow2(max_size_in);
1564  info->input_prec[0] = max_size_in;
1565  info->input_prec[1] = max_size_in;
1566  info->output_prec = max_size_in;
1567  }
1568  else
1569  {
1570  if(resize_1_8_pow2(output_size_true) < max_size_in)
1571  {
1572  max_size_in = resize_1_8_pow2(output_size_true);
1573  }
1574  info->output_prec = max_size_in;
1575  }
1576  if(current_op == "widen_mult_expr")
1577  {
1578  info->output_prec = info->input_prec[0] + info->input_prec[1];
1579  }
1580  info->real_output_nelem = info->base128_output_nelem = 0;
1581  }
1582  }
1583  else if(starts_with(current_op, "float_expr_") || starts_with(current_op, "fix_trunc_expr_") ||
1584  current_op == "dot_prod_expr" || current_op == "widen_sum_expr" || current_op == "widen_mult_hi_expr" ||
1585  current_op == "widen_mult_lo_expr" || current_op == "vec_unpack_hi_expr" ||
1586  current_op == "vec_unpack_lo_expr")
1587  {
1589  if(starts_with(current_op, "float_expr_") && max_size_in < 32)
1590  {
1591  max_size_in = 32;
1592  }
1593  auto nodeOutput_id = hls_manager->get_produced_value(function_index, node);
1594  if(nodeOutput_id)
1595  {
1596  const auto out_node = TreeM->CGetTreeReindex(nodeOutput_id);
1597  type = tree_helper::CGetType(out_node);
1599  tree_helper::IsUnionType(type) /*|| tree_helper::IsComplexType(type)*/)
1600  {
1601  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Output precision is 32");
1602  info->output_prec = 32;
1603  }
1604  else
1605  {
1606  info->output_prec = resize_1_8_pow2(tree_helper::Size(out_node));
1607  if(tree_helper::IsVectorType(type))
1608  {
1609  const auto element_type = tree_helper::CGetElements(type);
1610  const auto element_size = tree_helper::Size(element_type);
1611  info->base128_output_nelem = 128 / element_size;
1612  info->real_output_nelem = info->output_prec / element_size;
1613  info->output_prec = element_size;
1615  "---Number of output elements (base128): " + STR(info->base128_output_nelem) +
1616  " - Number of real output elements: " + STR(info->real_output_nelem) +
1617  " - Output precision: " + STR(info->output_prec));
1618  }
1619  else
1620  {
1621  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Output is not a vector");
1622  info->real_output_nelem = 0;
1623  info->base128_output_nelem = 0;
1624  }
1625  }
1626 
1628  if(starts_with(current_op, "fix_trunc_expr_") && info->output_prec < 32)
1629  {
1630  info->output_prec = 32;
1631  }
1632  }
1633  if(current_op == "dot_prod_expr")
1634  {
1635  max_size_in = info->output_prec / 2;
1636  min_n_elements = info->base128_output_nelem * 2;
1637  }
1638  }
1639  else if(current_op == "plus_expr" || current_op == "minus_expr" || current_op == "pointer_plus_expr" ||
1640  current_op == "ternary_plus_expr" || current_op == "ternary_pm_expr" || current_op == "ternary_mp_expr" ||
1641  current_op == "ternary_mm_expr" || current_op == "negate_expr" || current_op == "bit_and_expr" ||
1642  current_op == "bit_ior_expr" || current_op == "bit_xor_expr" || current_op == "bit_not_expr" ||
1643  current_op == "bit_ior_concat_expr" || current_op == "cond_expr" ||
1644  current_op == "vec_cond_expr"
1645  )
1646  {
1647  auto nodeOutput_id = hls_manager->get_produced_value(function_index, node);
1648  THROW_ASSERT(nodeOutput_id, "unexpected condition");
1649  const auto out_node = TreeM->CGetTreeReindex(nodeOutput_id);
1650  type = tree_helper::CGetType(out_node);
1651  auto out_prec = tree_helper::Size(out_node);
1652  if(tree_helper::IsVectorType(type))
1653  {
1654  const auto element_type = tree_helper::CGetElements(type);
1655  const auto element_size = tree_helper::Size(element_type);
1656  const auto output_size = resize_1_8_pow2(out_prec);
1657  info->real_output_nelem = output_size / element_size;
1658  info->base128_output_nelem = 128 / element_size;
1659  info->output_prec = element_size;
1660  }
1661  else
1662  {
1663  if(current_op == "plus_expr" || current_op == "minus_expr" || current_op == "pointer_plus_expr" ||
1664  current_op == "ternary_plus_expr" || current_op == "ternary_pm_expr" || current_op == "ternary_mp_expr" ||
1665  current_op == "ternary_mm_expr" || current_op == "negate_expr")
1666  {
1667  if(out_prec == 9 || out_prec == 17 || out_prec == 33)
1668  {
1669  --out_prec;
1670  max_size_in = out_prec;
1671  }
1672  }
1673  else if(current_op == "bit_and_expr" || current_op == "bit_ior_expr" || current_op == "bit_xor_expr" ||
1674  current_op == "bit_not_expr" || current_op == "bit_ior_concat_expr")
1675  {
1677  out_prec = std::min(out_prec, 64ull);
1678  }
1679  info->output_prec = resize_1_8_pow2(out_prec);
1680  info->real_output_nelem = 0;
1681  info->base128_output_nelem = 0;
1682  }
1683  if(current_op == "cond_expr" && max_size_in > 64 && info->node_kind == "VECTOR_BOOL")
1684  {
1685  max_size_in = 64;
1686  }
1687 
1688  if(info->output_prec >= max_size_in)
1689  {
1690  info->output_prec = max_size_in;
1691  info->base128_output_nelem = min_n_elements;
1692  info->real_output_nelem = min_n_elements;
1693  }
1694  else
1695  {
1696  max_size_in = info->output_prec;
1697  min_n_elements = info->base128_output_nelem;
1699  }
1700  }
1701  else if(current_op == "lshift_expr")
1702  {
1703  auto nodeOutput_id = hls_manager->get_produced_value(function_index, node);
1704  THROW_ASSERT(nodeOutput_id, "unexpected condition");
1705  const auto out_node = TreeM->CGetTreeReindex(nodeOutput_id);
1706  type = tree_helper::CGetType(out_node);
1707  info->output_prec = resize_1_8_pow2(tree_helper::Size(out_node));
1708  if(tree_helper::IsVectorType(type))
1709  {
1710  const auto element_type = tree_helper::CGetElements(type);
1711  const auto element_size = tree_helper::Size(element_type);
1712  info->real_output_nelem = info->output_prec / element_size;
1713  info->base128_output_nelem = 128 / element_size;
1714  info->output_prec = element_size;
1716  "---Type is " + STR(type->index) + " " + STR(type) +
1717  " - Number of output elements (base128): " + STR(info->base128_output_nelem) +
1718  " - Number of real output elements: " + STR(info->real_output_nelem) +
1719  " - Output precision: " + STR(info->output_prec));
1720  }
1721  else
1722  {
1723  if(is_second_constant && info->output_prec > 64)
1724  {
1725  info->output_prec = 64;
1726  max_size_in = 64;
1727  }
1728  info->real_output_nelem = 0;
1729  info->base128_output_nelem = 0;
1730  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Output is not a vector");
1731  }
1732  if(info->output_prec >= max_size_in)
1733  {
1734  max_size_in = info->output_prec;
1735  min_n_elements = info->base128_output_nelem;
1737  }
1738  else
1739  {
1740  info->output_prec = max_size_in;
1741  info->base128_output_nelem = min_n_elements;
1742  info->real_output_nelem = min_n_elements;
1743  }
1744  }
1745  else if(current_op == "rshift_expr")
1746  {
1747  if(max_size_in > 64)
1748  {
1749  if(!is_second_constant)
1750  {
1751  THROW_WARNING(
1752  "A bad estimation of the timing of the rshift_expr operator will happen. This may occur when a "
1753  "non-constant bit reference of a long ac_type is used. Unrolling such a part may fix the issue.");
1754  }
1755  max_size_in = 64;
1756  }
1757  info->output_prec = max_size_in;
1758  info->base128_output_nelem = min_n_elements;
1759  info->real_output_nelem = min_n_elements;
1760  }
1761  else
1762  {
1763  info->output_prec = max_size_in;
1764  info->base128_output_nelem = min_n_elements;
1765  info->real_output_nelem = min_n_elements;
1766  }
1767  size_t n_inputs = info->input_prec.size();
1768  if(current_op != "widen_mult_expr" && current_op != "mult_expr")
1769  {
1770  for(unsigned int i = 0; i < n_inputs; ++i)
1771  {
1772  if(info->input_prec[i] != 0)
1773  {
1774  info->input_prec[i] = max_size_in;
1775  }
1776  }
1777  }
1778  for(auto& n_elements : info->base128_input_nelem)
1779  {
1780  if(n_elements)
1781  {
1782  n_elements = min_n_elements;
1783  }
1784  }
1785 
1787  if(current_op == "vec_perm_expr")
1788  {
1789  if(info->input_prec[2] == 0)
1790  {
1791  std::swap(info->input_prec[2], info->input_prec[1]);
1792  std::swap(info->base128_input_nelem[2], info->base128_input_nelem[1]);
1793  std::swap(info->real_input_nelem[2], info->real_input_nelem[1]);
1794  }
1795  }
1796  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Got node type precision of " + GET_NAME(g, node));
1797 }
1798 
1799 unsigned int updatecopy_HLS_constraints_functor::operator()(const unsigned int name) const
1800 {
1801  return tech[name];
1802 }
1803 
1804 void updatecopy_HLS_constraints_functor::update(const unsigned int name, int delta)
1805 {
1806  if(tech[name] == INFINITE_UINT)
1807  {
1808  return;
1809  }
1810  tech[name] = static_cast<unsigned int>(static_cast<int>(tech[name]) + delta);
1811 }
1812 
1814  const AllocationInformationRef allocation_information)
1815  : tech(allocation_information->tech_constraints)
1816 {
1817 }
1818 
1819 unsigned long long AllocationInformation::get_prec(const unsigned int fu_name) const
1820 {
1821  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
1822  THROW_ASSERT(precision_map.find(fu_name) != precision_map.end(), "missing the precision of " + STR(fu_name));
1823  return precision_map.find(fu_name)->second != 0 ? precision_map.find(fu_name)->second : 32;
1824 }
1825 
1826 double AllocationInformation::mux_time_unit(unsigned long long fu_prec) const
1827 {
1828  return estimate_muxNto1_delay(fu_prec, 2);
1829 }
1830 
1831 double AllocationInformation::mux_time_unit_raw(unsigned long long fu_prec) const
1832 {
1833  const technology_managerRef TM = HLS_D->get_technology_manager();
1834  technology_nodeRef f_unit_mux =
1835  TM->get_fu(MUX_GATE_STD + STR("_1_") + STR(fu_prec) + "_" + STR(fu_prec) + "_" + STR(fu_prec), LIBRARY_STD_FU);
1836  THROW_ASSERT(f_unit_mux, "Library miss component: " + std::string(MUX_GATE_STD) + STR("_1_") + STR(fu_prec) + "_" +
1837  STR(fu_prec) + "_" + STR(fu_prec));
1838  auto* fu_br = GetPointer<functional_unit>(f_unit_mux);
1839  technology_nodeRef op_mux_node = fu_br->get_operation(MUX_GATE_STD);
1840  auto* op_mux = GetPointer<operation>(op_mux_node);
1841  double mux_delay = time_m_execution_time(op_mux) - get_setup_hold_time();
1842  if(mux_delay <= 0.0)
1843  {
1844  mux_delay = get_setup_hold_time() / 2;
1845  }
1846  //#define MUX_MARGIN 1.3
1847  // return mux_delay*ALLOCATION_MUX_MARGIN+get_setup_hold_time();
1848  // return mux_delay+get_setup_hold_time()*ALLOCATION_MUX_MARGIN;
1849  return mux_delay;
1850 }
1851 
1852 void AllocationInformation::print(std::ostream& os) const
1853 {
1854  auto fu_end = list_of_FU.end();
1855  unsigned int index = 0;
1856  for(auto fu = list_of_FU.begin(); fu != fu_end; ++fu)
1857  {
1858  os << index << " ";
1859  index++;
1860  (*fu)->print(os);
1861  }
1862  if(!node_id_to_fus.empty())
1863  {
1864  os << "Op_name relation with functional unit name and operations.\n";
1865  for(const auto& node_id : node_id_to_fus)
1866  {
1867  for(const auto fu : node_id.second)
1868  {
1869  os << " [" << STR(node_id.first.first) << ", <" << list_of_FU[fu]->get_name() << ">]" << std::endl;
1870  }
1871  }
1872  }
1873 }
1874 
1875 #ifndef NDEBUG
1877 {
1878  if(debug_level >= DEBUG_LEVEL_VERBOSE)
1879  {
1880  PRINT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "\nDumping the list of all the fixed bindings FU <-> node");
1881  for(const auto& bind : binding)
1882  {
1883  if(bind.first == ENTRY_ID || bind.first == EXIT_ID)
1884  {
1885  continue;
1886  }
1887  PRINT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, " Vertex " + STR(bind.first));
1888  PRINT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level,
1889  " Corresponding operation: " +
1891  GetPointer<const gimple_node>(TreeM->CGetTreeNode(bind.first))->operation) +
1892  "(" + STR(bind.second.second) + ")");
1893  auto* fu = dynamic_cast<functional_unit*>(GetPointer<functional_unit>(list_of_FU[bind.second.second]));
1894  PRINT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, " Vertex bound to: " + fu->get_name());
1895  }
1896 
1897  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "Dumping the list of all the possible bindings FU <-> node");
1898  for(const auto& bind : node_id_to_fus)
1899  {
1900  if(bind.first.first == ENTRY_ID || bind.first.first == EXIT_ID || bind.first.first)
1901  {
1902  continue;
1903  }
1904  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level,
1905  " Vertex " + STR(bind.first.first) + "(" +
1906  GetPointer<const gimple_node>(TreeM->CGetTreeNode(bind.first.first))->operation + ")");
1907  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, " Operation can be implemented by the following FUs:");
1908  for(const auto fu_id : bind.second)
1909  {
1910  auto* fu = dynamic_cast<functional_unit*>(GetPointer<functional_unit>(list_of_FU[fu_id]));
1911  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level,
1912  " FU name: " + fu->get_name() + "(" + STR(fu_id) + ")");
1913  }
1914  }
1915  }
1916 }
1917 #endif
1918 
1919 technology_nodeRef AllocationInformation::get_fu(const std::string& fu_name, const HLS_managerConstRef hls_manager)
1920 {
1921  const HLS_deviceRef HLS_D = hls_manager->get_HLS_device();
1922  std::string library_name = HLS_D->get_technology_manager()->get_library(fu_name);
1923  if(library_name == "")
1924  {
1925  return technology_nodeRef();
1926  }
1927  return HLS_D->get_technology_manager()->get_fu(fu_name, library_name);
1928 }
1929 
1930 unsigned int AllocationInformation::GetCycleLatency(const vertex operationID) const
1931 {
1932  return GetCycleLatency(op_graph->CGetOpNodeInfo(operationID)->GetNodeId());
1933 }
1934 
1935 unsigned int AllocationInformation::GetCycleLatency(const unsigned int operationID) const
1936 {
1938  "-->Get cycle latency of " + ((operationID != ENTRY_ID && operationID != EXIT_ID) ?
1939  STR(TreeM->CGetTreeNode(operationID)) :
1940  "Entry/Exit"));
1941  if(CanImplementSetNotEmpty(operationID))
1942  {
1943  const auto actual_latency = get_cycles(GetFuType(operationID), operationID);
1944  const auto ret_value = actual_latency != 0 ? actual_latency : 1;
1945  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Latency of allocation fu is " + STR(ret_value));
1946  return ret_value;
1947  }
1948 
1949  THROW_ASSERT(operationID != ENTRY_ID && operationID != EXIT_ID, "Entry or exit not allocated");
1950  const auto tn = TreeM->CGetTreeNode(operationID);
1951  const auto ga = GetPointer<const gimple_assign>(tn);
1952  if(ga)
1953  {
1954  const auto right_kind = GET_CONST_NODE(ga->op1)->get_kind();
1955  if(right_kind == widen_mult_expr_K || right_kind == mult_expr_K)
1956  {
1958  "<--Latency of not allocated fu is 1: possibly inaccurate");
1959  const auto data_bitsize = tree_helper::Size(ga->op0);
1960  const auto fu_prec = resize_1_8_pow2(data_bitsize);
1961  const auto in_prec = right_kind == mult_expr_K ? fu_prec : (fu_prec / 2);
1962  const auto fu_name =
1963  tree_node::GetString(right_kind) + "_FU_" + STR(in_prec) + "_" + STR(in_prec) + "_" + STR(fu_prec) + "_0";
1964  const auto new_stmt_temp = HLS_D->get_technology_manager()->get_fu(fu_name, LIBRARY_STD_FU);
1965  THROW_ASSERT(new_stmt_temp, "Functional unit '" + fu_name + "' not found");
1966  const auto new_stmt_fu = GetPointer<const functional_unit>(new_stmt_temp);
1967  const auto new_stmt_op_temp = new_stmt_fu->get_operation(tree_node::GetString(right_kind));
1968  const auto new_stmt_op = GetPointer<operation>(new_stmt_op_temp);
1969  return new_stmt_op->time_m->get_cycles();
1970  }
1971  else if(right_kind == call_expr_K)
1972  {
1973  return 0;
1974  }
1975  else if(right_kind == ssa_name_K || right_kind == integer_cst_K || right_kind == cond_expr_K ||
1976  right_kind == vec_cond_expr_K || right_kind == nop_expr_K || right_kind == addr_expr_K ||
1977  right_kind == convert_expr_K || right_kind == lut_expr_K || right_kind == extract_bit_expr_K ||
1978  right_kind == bit_ior_concat_expr_K || right_kind == truth_not_expr_K || right_kind == bit_not_expr_K ||
1979  right_kind == negate_expr_K || right_kind == truth_and_expr_K || right_kind == truth_or_expr_K ||
1980  right_kind == truth_xor_expr_K || right_kind == bit_and_expr_K || right_kind == bit_ior_expr_K ||
1981  right_kind == bit_xor_expr_K || right_kind == rshift_expr_K || right_kind == lshift_expr_K ||
1982  right_kind == plus_expr_K || right_kind == pointer_plus_expr_K || right_kind == minus_expr_K ||
1983  right_kind == eq_expr_K || right_kind == ne_expr_K || right_kind == lt_expr_K ||
1984  right_kind == le_expr_K || right_kind == gt_expr_K || right_kind == ge_expr_K ||
1985  right_kind == ternary_plus_expr_K || right_kind == ternary_mp_expr_K || right_kind == ternary_pm_expr_K ||
1986  right_kind == ternary_mm_expr_K)
1987  {
1988  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Latency of not allocated fu is 1");
1989  return 1;
1990  }
1991  THROW_UNREACHABLE("Unsupported right part (" + tree_node::GetString(right_kind) + ") of gimple assignment " +
1992  ga->ToString());
1993  }
1994  else if(tn->get_kind() == gimple_multi_way_if_K || tn->get_kind() == gimple_cond_K ||
1995  tn->get_kind() == gimple_phi_K || tn->get_kind() == gimple_nop_K || tn->get_kind() == gimple_return_K)
1996  {
1997  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Latency of not allocated fu is 1");
1998  return 1;
1999  }
2000 
2001  return 0;
2002 }
2003 
2004 std::pair<double, double> AllocationInformation::GetTimeLatency(const vertex operationID,
2005  const unsigned int functional_unit,
2006  const unsigned int stage) const
2007 {
2008  return GetTimeLatency(op_graph->CGetOpNodeInfo(operationID)->GetNodeId(), functional_unit, stage);
2009 }
2010 
2011 std::pair<double, double> AllocationInformation::GetTimeLatency(const unsigned int operation_index,
2012  const unsigned int functional_unit_type,
2013  const unsigned int stage) const
2014 {
2015  if(operation_index == ENTRY_ID || operation_index == EXIT_ID)
2016  {
2017  return std::pair<double, double>(0.0, 0.0);
2018  }
2019  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Computing time latency of " + STR(operation_index));
2020 
2021  const unsigned int time_operation_index = [&]() -> unsigned int {
2022  if(operation_index == ENTRY_ID || operation_index == EXIT_ID)
2023  {
2024  return operation_index;
2025  }
2026  if(CanImplementSetNotEmpty(operation_index))
2027  {
2028  return operation_index;
2029  }
2030  return operation_index;
2031  }();
2033  const auto num_cycles = GetCycleLatency(time_operation_index);
2034  if(stage > 0 && stage < num_cycles - 1)
2035  {
2036  const double ret_value = HLS_C->get_clock_period_resource_fraction() * HLS_C->get_clock_period();
2037  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Time is " + STR(ret_value) + "," + STR(ret_value));
2038  return std::pair<double, double>(ret_value, ret_value);
2039  }
2040 
2041  if(CanImplementSetNotEmpty(time_operation_index))
2042  {
2043  unsigned int fu_type;
2044  if(functional_unit_type != fu_binding::UNKNOWN)
2045  {
2046  fu_type = functional_unit_type;
2047  }
2048  else
2049  {
2050  fu_type = GetFuType(time_operation_index);
2051  }
2053  "---Functional unit name is " + get_fu_name(fu_type).first);
2054  double connection_contribute = 0;
2056  double actual_execution_time = get_execution_time(fu_type, time_operation_index);
2057  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Initial execution time " + STR(actual_execution_time));
2058  auto n_ins = [&]() -> unsigned {
2059  unsigned res = 0;
2060  auto tn = TreeM->CGetTreeNode(time_operation_index);
2061  const auto ga = GetPointer<const gimple_assign>(tn);
2062  if(ga && GET_NODE(ga->op1)->get_kind() == lut_expr_K)
2063  {
2064  auto le = GetPointer<lut_expr>(GET_NODE(ga->op1));
2065  if(le->op8)
2066  {
2067  res = 8;
2068  }
2069  else if(le->op7)
2070  {
2071  res = 7;
2072  }
2073  else if(le->op6)
2074  {
2075  res = 6;
2076  }
2077  else if(le->op5)
2078  {
2079  res = 5;
2080  }
2081  else if(le->op4)
2082  {
2083  res = 4;
2084  }
2085  else if(le->op3)
2086  {
2087  res = 3;
2088  }
2089  else if(le->op2)
2090  {
2091  res = 2;
2092  }
2093  else if(le->op1)
2094  {
2095  res = 1;
2096  }
2097  else
2098  {
2099  THROW_ERROR("unexpected condition");
2100  }
2101  }
2102  return res;
2103  }();
2104  double initial_execution_time =
2105  actual_execution_time -
2106  get_correction_time(
2107  fu_type, GetPointer<const gimple_node>(TreeM->CGetTreeNode(time_operation_index))->operation, n_ins);
2109  "---Initial corrected execution time " + STR(initial_execution_time));
2110  double op_execution_time = initial_execution_time;
2111  if(op_execution_time <= 0.0)
2112  {
2113  op_execution_time = epsilon;
2114  }
2115 
2117  double actual_stage_period;
2118  actual_stage_period = get_stage_period(fu_type, time_operation_index);
2119  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---actual_stage_period=" + STR(actual_stage_period));
2120  double initial_stage_period = 0.0;
2121  if(get_initiation_time(fu_type, time_operation_index) > 0)
2122  {
2123  if(actual_stage_period > HLS_C->get_clock_period_resource_fraction() * HLS_C->get_clock_period())
2124  {
2125  actual_stage_period = HLS_C->get_clock_period_resource_fraction() * HLS_C->get_clock_period();
2126  }
2127  initial_stage_period =
2128  actual_stage_period -
2129  get_correction_time(
2130  fu_type, GetPointer<const gimple_node>(TreeM->CGetTreeNode(time_operation_index))->operation, n_ins);
2131  }
2132  double stage_period = initial_stage_period;
2133 
2134  THROW_ASSERT(get_initiation_time(fu_type, time_operation_index) == 0 || stage_period > 0.0,
2135  "unexpected condition: " + get_fu_name(fu_type).first + " Initiation time " +
2136  STR(get_initiation_time(fu_type, time_operation_index)) + " Stage period " + STR(stage_period));
2137 
2138  if(stage_period > 0)
2139  {
2140  stage_period += connection_contribute;
2141  }
2142  else
2143  {
2144  op_execution_time += connection_contribute;
2145  }
2147  "<--Time is " + STR(op_execution_time) + "," + STR(stage_period));
2148  return std::make_pair(op_execution_time, stage_period);
2149  }
2150  else
2151  {
2152  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Not yet available: building time model");
2153  THROW_ASSERT(time_operation_index != ENTRY_ID && time_operation_index != EXIT_ID, "Entry or exit not allocated");
2154  const auto op_stmt = TreeM->CGetTreeNode(time_operation_index);
2155  const auto op_stmt_kind = op_stmt->get_kind();
2156  if(op_stmt_kind == gimple_assign_K)
2157  {
2158  const auto ga = GetPointerS<const gimple_assign>(op_stmt);
2159  const auto op1_kind = GET_CONST_NODE(ga->op1)->get_kind();
2160  if(op1_kind == ssa_name_K || op1_kind == integer_cst_K || op1_kind == convert_expr_K ||
2161  op1_kind == nop_expr_K || op1_kind == addr_expr_K || op1_kind == bit_ior_concat_expr_K ||
2162  op1_kind == extract_bit_expr_K)
2163  {
2164  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Time is 0.0,0.0");
2165  return std::make_pair(0.0, 0.0);
2166  }
2167  else if((op1_kind == rshift_expr_K || op1_kind == lshift_expr_K) &&
2168  GET_CONST_NODE(GetPointerS<const binary_expr>(GET_CONST_NODE(ga->op1))->op1)->get_kind() ==
2169  integer_cst_K)
2170  {
2171  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Time is 0.0,0.0");
2172  return std::make_pair(0.0, 0.0);
2173  }
2174  else if(op1_kind == cond_expr_K || op1_kind == vec_cond_expr_K)
2175  {
2176  THROW_ASSERT(tree_helper::Size(GetPointerS<const ternary_expr>(GET_CONST_NODE(ga->op1))->op0) == 1,
2177  "Cond expr not allocated " + ga->op1->ToString());
2179  const auto data_bitsize = tree_helper::Size(ga->op0);
2180  const auto fu_prec = resize_1_8_pow2(data_bitsize);
2181  const auto op_execution_time = mux_time_unit(fu_prec);
2183  "<--Time is mux time (precision is " + STR(fu_prec) + ") " + STR(op_execution_time) +
2184  ",0.0");
2185  return std::make_pair(op_execution_time, 0.0);
2186  }
2187 
2188  const auto data_bitsize = tree_helper::Size(ga->op0);
2189  const auto fu_prec = resize_1_8_pow2(data_bitsize);
2190  std::string fu_name;
2191  if(op1_kind == widen_mult_expr_K || op1_kind == mult_expr_K)
2192  {
2193  const auto in_prec = op1_kind == mult_expr_K ? fu_prec : (fu_prec / 2);
2194  fu_name =
2195  tree_node::GetString(op1_kind) + "_FU_" + STR(in_prec) + "_" + STR(in_prec) + "_" + STR(fu_prec) + "_0";
2196  const auto new_stmt_temp = HLS_D->get_technology_manager()->get_fu(fu_name, LIBRARY_STD_FU);
2197  THROW_ASSERT(new_stmt_temp, "Functional unit '" + fu_name + "' not found");
2198  const auto new_stmt_fu = GetPointerS<const functional_unit>(new_stmt_temp);
2199  const auto new_stmt_op_temp = new_stmt_fu->get_operation(tree_node::GetString(op1_kind));
2200  const auto new_stmt_op = GetPointerS<operation>(new_stmt_op_temp);
2201  auto op_execution_time = time_m_execution_time(new_stmt_op);
2203  "---Uncorrected execution time is " + STR(op_execution_time));
2204  op_execution_time = op_execution_time - get_setup_hold_time();
2205  double actual_stage_period;
2206  actual_stage_period = time_m_stage_period(new_stmt_op);
2208  "---actual_stage_period=" + STR(actual_stage_period));
2209  double initial_stage_period = 0.0;
2210  if(new_stmt_op->time_m->get_initiation_time() > 0)
2211  {
2212  if(actual_stage_period > HLS_C->get_clock_period_resource_fraction() * HLS_C->get_clock_period())
2213  {
2214  actual_stage_period = HLS_C->get_clock_period_resource_fraction() * HLS_C->get_clock_period();
2215  }
2216  initial_stage_period = actual_stage_period - get_setup_hold_time();
2217  }
2218  double stage_period = initial_stage_period;
2220  "<--Time is " + STR(op_execution_time) + "," + STR(stage_period));
2221  return std::make_pair(op_execution_time, stage_period);
2222  }
2223  else if(op1_kind == lut_expr_K)
2224  {
2225  fu_name = tree_node::GetString(op1_kind) + "_FU";
2226  }
2227  else if(GetPointer<const unary_expr>(GET_CONST_NODE(ga->op1)))
2228  {
2229  fu_name = tree_node::GetString(op1_kind) + "_FU_" + STR(fu_prec) + "_" + STR(fu_prec);
2230  }
2231  else if(GetPointer<const binary_expr>(GET_CONST_NODE(ga->op1)))
2232  {
2233  fu_name = tree_node::GetString(op1_kind) + "_FU_" + STR(fu_prec) + "_" + STR(fu_prec) + "_" + STR(fu_prec);
2234  }
2235  else if(GetPointer<const ternary_expr>(GET_CONST_NODE(ga->op1)))
2236  {
2237  fu_name = tree_node::GetString(op1_kind) + "_FU_" + STR(fu_prec) + "_" + STR(fu_prec) + "_" + STR(fu_prec) +
2238  "_" + STR(fu_prec);
2239  }
2240  else
2241  {
2242  THROW_UNREACHABLE("Latency of " + op_stmt->ToString() + " cannot be computed");
2243  }
2244  const auto new_stmt_temp = HLS_D->get_technology_manager()->get_fu(fu_name, LIBRARY_STD_FU);
2245  THROW_ASSERT(new_stmt_temp, "Functional unit '" + fu_name + "' not found");
2246  const auto new_stmt_fu = GetPointerS<const functional_unit>(new_stmt_temp);
2247  const auto new_stmt_op_temp = new_stmt_fu->get_operation(tree_node::GetString(op1_kind));
2248  const auto new_stmt_op = GetPointerS<operation>(new_stmt_op_temp);
2249  auto op_execution_time = time_m_execution_time(new_stmt_op);
2251  "---Uncorrected execution time is " + STR(op_execution_time));
2252  op_execution_time = op_execution_time - get_setup_hold_time();
2253  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Time is " + STR(op_execution_time) + ",0.0");
2254  return std::make_pair(op_execution_time, 0.0);
2255  }
2256  else if(op_stmt_kind == gimple_multi_way_if_K || op_stmt_kind == gimple_cond_K)
2257  {
2258  auto controller_delay = estimate_controller_delay_fb();
2259  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Time is " + STR(controller_delay) + ",0.0");
2260  return std::make_pair(controller_delay, 0.0);
2261  }
2262  else if(op_stmt_kind == gimple_phi_K || op_stmt_kind == gimple_nop_K || op_stmt_kind == gimple_return_K)
2263  {
2264  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Time is 0.0,0.0");
2265  return std::make_pair(0.0, 0.0);
2266  }
2267  THROW_UNREACHABLE("Latency of " + op_stmt->ToString() + " cannot be computed");
2268  return std::make_pair(0.0, 0.0);
2269  }
2270 }
2271 
2272 double AllocationInformation::GetPhiConnectionLatency(const unsigned int statement_index) const
2273 {
2275  "-->Computing phi connection delay of " + STR(statement_index));
2277  const auto phi_in_degree = [&]() -> size_t {
2278  size_t ret_value = 0;
2279  if(statement_index == ENTRY_ID || statement_index == EXIT_ID)
2280  {
2281  return 0;
2282  }
2283  const auto tn = TreeM->CGetTreeNode(statement_index);
2284  if(tn->get_kind() != gimple_assign_K)
2285  {
2286  return 0;
2287  }
2288  const auto ga = GetPointer<const gimple_assign>(tn);
2289  if(GET_NODE(ga->op0)->get_kind() != ssa_name_K)
2290  {
2291  return 0;
2292  }
2293  const auto sn = GetPointer<const ssa_name>(GET_NODE(ga->op0));
2294  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Analyzing uses of " + sn->ToString());
2295  for(const auto& use : sn->CGetUseStmts())
2296  {
2297  const auto target = GET_NODE(use.first);
2298  if(target->get_kind() == gimple_phi_K)
2299  {
2300  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Phi: " + target->ToString());
2301  const auto gp = GetPointer<const gimple_phi>(target);
2302  CustomOrderedSet<unsigned int> phi_inputs;
2303  for(const auto& def_edge : gp->CGetDefEdgesList())
2304  {
2305  if(def_edge.first->index && !behavioral_helper->is_a_constant(def_edge.first->index))
2306  {
2307  phi_inputs.insert(def_edge.first->index);
2308  }
2309  }
2310  auto curr_in_degree = static_cast<size_t>(phi_inputs.size());
2311  if(curr_in_degree > 4)
2312  {
2313  curr_in_degree = 4;
2314  }
2315  ret_value = std::max(ret_value, curr_in_degree);
2316  }
2317  }
2318  return ret_value;
2319  }();
2320  if(phi_in_degree == 0)
2321  {
2322  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Delay is 0.0");
2323  return 0.0;
2324  }
2325  const auto statement = TreeM->CGetTreeNode(statement_index);
2326  THROW_ASSERT(statement->get_kind() == gimple_assign_K, statement->ToString());
2327  const auto sn = GetPointerS<const gimple_assign>(statement)->op0;
2328  THROW_ASSERT(sn, "");
2329  const auto precision = resize_1_8_pow2(tree_helper::Size(sn));
2330  const auto mux_time = estimate_muxNto1_delay(precision, static_cast<unsigned int>(phi_in_degree));
2332  "<--Delay (" + STR(phi_in_degree) + " with " + STR(precision) + " bits) is " + STR(mux_time));
2333  return mux_time;
2334 }
2335 
2336 double AllocationInformation::GetCondExprTimeLatency(const unsigned int operation_index) const
2337 {
2338  const auto tn = TreeM->CGetTreeReindex(operation_index);
2339  const auto gp = GetPointer<const gimple_phi>(GET_CONST_NODE(tn));
2340  THROW_ASSERT(gp, "Tree node is " + STR(tn));
2343  const auto type = tree_helper::CGetType(tn);
2344  const auto data_bitsize = tree_helper::Size(type);
2345  const auto fu_prec = resize_1_8_pow2(data_bitsize);
2346  return mux_time_unit(fu_prec);
2347 }
2348 
2350 {
2351  return GetFuType(op_graph->CGetOpNodeInfo(operation)->GetNodeId());
2352 }
2353 
2354 unsigned int AllocationInformation::GetFuType(const unsigned int operation) const
2355 {
2356  unsigned int fu_type = 0;
2357  if(not is_vertex_bounded_with(operation, fu_type))
2358  {
2359  const CustomOrderedSet<unsigned int>& fu_set = can_implement_set(operation);
2360  if(fu_set.size() > 1)
2361  {
2362  for(const auto fu : fu_set)
2363  {
2364  INDENT_OUT_MEX(0, 0, get_fu_name(fu).first);
2365  }
2366  THROW_UNREACHABLE("Multiple fus not supported: " + STR(TreeM->CGetTreeNode(operation)));
2367  }
2368  else
2369  {
2370  return *(fu_set.begin());
2371  }
2372  }
2373  return fu_type;
2374 }
2375 
2376 double AllocationInformation::mux_area_unit_raw(unsigned long long fu_prec) const
2377 {
2378  const technology_managerRef TM = HLS_D->get_technology_manager();
2379  technology_nodeRef f_unit_mux =
2380  TM->get_fu(MUX_GATE_STD + STR("_1_") + STR(fu_prec) + "_" + STR(fu_prec) + "_" + STR(fu_prec), LIBRARY_STD_FU);
2381  THROW_ASSERT(f_unit_mux, "Library miss component: " + std::string(MUX_GATE_STD) + STR("_1_") + STR(fu_prec) + "_" +
2382  STR(fu_prec) + "_" + STR(fu_prec));
2383  auto* fu_mux = GetPointer<functional_unit>(f_unit_mux);
2384  auto area = fu_mux->area_m->get_resource_value(area_info::SLICE_LUTS);
2385  if(area == 0.0)
2386  {
2387  area = fu_mux->area_m->get_area_value() - 1.0;
2388  }
2389  return area;
2390 }
2391 
2392 double AllocationInformation::estimate_mux_area(unsigned int fu_name) const
2393 {
2394  auto fu_prec = get_prec(fu_name);
2395  fu_prec = resize_1_8_pow2(fu_prec);
2396  return estimate_muxNto1_area(fu_prec, 2);
2397 }
2398 
2400 {
2401  return 0.5 * EstimateControllerDelay();
2402 }
2403 
2405 {
2406  const double states_number_normalization = parameters->IsParameter("StatesNumberNormalization") ?
2407  parameters->GetParameter<double>("StatesNumberNormalization") :
2409  if(not parameters->getOption<bool>(OPT_estimate_logic_and_connections))
2410  {
2411  return 0.0;
2412  }
2413  size_t n_states =
2414  boost::num_vertices(*hls_manager->CGetFunctionBehavior(function_index)->CGetBBGraph(FunctionBehavior::BB)) +
2415  get_n_complex_operations();
2416  double n_states_factor = static_cast<double>(n_states) / NUM_CST_allocation_default_states_number_normalization_BB;
2417  if(hls->STG && hls->STG->get_number_of_states())
2418  {
2419  n_states = hls->STG->get_number_of_states();
2420  if(n_states == 1)
2421  {
2422  return 0.0;
2423  }
2424  n_states_factor = static_cast<double>(n_states) / states_number_normalization;
2425  }
2426  unsigned int fu_prec = 16;
2427  const technology_managerRef TM = HLS_D->get_technology_manager();
2428  technology_nodeRef f_unit =
2429  TM->get_fu(MULTIPLIER_STD + std::string("_") + STR(fu_prec) + "_" + STR(fu_prec) + "_" + STR(fu_prec) + "_0",
2430  LIBRARY_STD_FU);
2431  THROW_ASSERT(f_unit, "Library miss component: " + std::string(MULTIPLIER_STD) + std::string("_") + STR(fu_prec) +
2432  "_" + STR(fu_prec) + "_" + STR(fu_prec) + "_0");
2433  auto* fu = GetPointer<functional_unit>(f_unit);
2434  technology_nodeRef op_node = fu->get_operation("mult_expr");
2435  auto* op = GetPointer<operation>(op_node);
2436  double delay = time_m_execution_time(op);
2437  delay = delay * controller_delay_multiplier *
2438  ((1 - exp(-n_states_factor)) +
2440  if(delay < 2 * get_setup_hold_time())
2441  {
2442  delay = 2 * get_setup_hold_time();
2443  }
2445  "---Controller delay is " + STR(delay) + " while n_states is " + STR(n_states));
2446  return delay;
2447 }
2448 
2449 std::string AllocationInformation::get_latency_string(const std::string& lat) const
2450 {
2451  if(lat == "2")
2452  {
2453  return std::string("");
2454  }
2455  else if(lat == "3")
2456  {
2457  return std::string("_3");
2458  }
2459  else if(lat == "4")
2460  {
2461  return std::string("_4");
2462  }
2463  else
2464  {
2465  THROW_ERROR("unexpected BRAM latency:" + lat);
2466  }
2467  return "";
2468 }
2469 
2470 #define ARRAY_CORRECTION 0
2471 double AllocationInformation::get_correction_time(unsigned int fu, const std::string& operation_name,
2472  unsigned int n_ins) const
2473 {
2474  double res_value = get_setup_hold_time();
2475  technology_nodeRef current_fu = get_fu(fu);
2476  std::string memory_type = GetPointer<functional_unit>(current_fu)->memory_type;
2477  std::string memory_ctrl_type = GetPointer<functional_unit>(current_fu)->memory_ctrl_type;
2479  "-->Computing correction time of '" + operation_name + "'" +
2480  (memory_type != "" ? "(" + memory_type + ")" : "") +
2481  (memory_ctrl_type != "" ? "(" + memory_ctrl_type + ")" : ""));
2482  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Setup-Hold-time: " + STR(res_value));
2483  unsigned long long elmt_bitsize = 0;
2484  bool is_read_only_correction = false;
2485  bool is_proxied_correction = false;
2486  bool is_a_proxy = false;
2487  bool is_private_correction = false;
2488  bool is_single_variable = false;
2489  auto single_var_lambda = [&](unsigned var) -> bool {
2490  unsigned int type_index = tree_helper::get_type_index(TreeM, var);
2491  if(tree_helper::is_an_array(TreeM, type_index) || tree_helper::is_a_struct(TreeM, type_index) ||
2492  tree_helper::is_an_union(TreeM, type_index))
2493  {
2494  return false;
2495  }
2496  else
2497  {
2498  return true;
2499  }
2500  };
2501 
2502 #if 0
2503  if(GetPointer<functional_unit>(current_fu)->component_timing_alias != "")
2505  {
2506  std::string component_name = GetPointer<functional_unit>(current_fu)->component_timing_alias;
2507  std::string library = HLS_D->get_technology_manager()->get_library(component_name);
2508  technology_nodeRef f_unit_alias = HLS_D->get_technology_manager()->get_fu(component_name, library);
2509  THROW_ASSERT(f_unit_alias, "Library miss component: " + component_name);
2510  functional_unit * fu_alias = GetPointer<functional_unit>(f_unit_alias);
2511  technology_nodeRef op_alias_node = fu_alias->get_operation(operation_name);
2512  operation * op_alias = op_alias_node ? GetPointer<operation>(op_alias_node) : GetPointer<operation>(fu_alias->get_operations().front());
2513  double alias_exec_time = op_alias->time_m->get_initiation_time() != 0u ? time_m_stage_period(op_alias) : time_m_execution_time(op_alias);
2514  functional_unit * fu_cur = GetPointer<functional_unit>(current_fu);
2515  technology_nodeRef op_cur_node = fu_cur->get_operation(operation_name);
2516  operation * op_cur = GetPointer<operation>(op_cur_node);
2517  double cur_exec_time = op_cur->time_m->get_initiation_time() != 0u ? time_m_stage_period(op_cur) : time_m_execution_time(op_cur);
2518  res_value += cur_exec_time - alias_exec_time;
2519  }
2520 #endif
2521  if(memory_type == MEMORY_TYPE_SYNCHRONOUS_UNALIGNED)
2522  {
2524  "---Applying memory correction for MEMORY_TYPE_SYNCHRONOUS_UNALIGNED");
2525  unsigned var = get_memory_var(fu);
2526  if(!Rmem->is_a_proxied_variable(var))
2527  {
2528  is_proxied_correction = true;
2529  }
2530  else if(Rmem->is_private_memory(var))
2531  {
2532  is_private_correction = true;
2533  }
2534  if(Rmem->is_read_only_variable(var))
2535  {
2536  is_read_only_correction = true;
2537  }
2538  is_single_variable = single_var_lambda(var);
2539 
2540  elmt_bitsize = Rmem->get_bram_bitsize();
2541 
2542 #if ARRAY_CORRECTION
2543  auto type_index = tree_helper::get_type_index(TreeM, var);
2544  if(tree_helper::is_an_array(TreeM, type_index))
2545  {
2546  std::vector<unsigned int> dims;
2547  tree_helper::get_array_dimensions(TreeM, type_index, dims);
2548  unsigned int n_not_power_of_two = 0;
2549  for(auto idx : dims)
2550  if(idx & (idx - 1))
2551  ++n_not_power_of_two;
2552  if(dims.size() > 1 && n_not_power_of_two > 0)
2553  {
2554  const technology_managerRef TM = HLS_D->get_technology_manager();
2555  auto bus_addr_bitsize = resize_1_8_pow2(address_bitsize);
2556  technology_nodeRef f_unit =
2557  TM->get_fu(ADDER_STD + std::string("_" + STR(bus_addr_bitsize) + "_" + STR(bus_addr_bitsize) + "_" +
2558  STR(bus_addr_bitsize)),
2559  LIBRARY_STD_FU);
2560  THROW_ASSERT(f_unit, "Library miss component: " + std::string(ADDER_STD) +
2561  std::string("_" + STR(bus_addr_bitsize) + "_" + STR(bus_addr_bitsize) + "_" +
2562  STR(bus_addr_bitsize)));
2563  functional_unit* Fu = GetPointer<functional_unit>(f_unit);
2564  technology_nodeRef op_node = Fu->get_operation("plus_expr");
2565  operation* op = GetPointer<operation>(op_node);
2566  double delay = time_m_execution_time(op) - get_setup_hold_time();
2567  unsigned int n_levels = 0;
2568  for(; dims.size() >= (1u << n_levels); ++n_levels)
2569  ;
2570  res_value -= (n_levels - 1) * delay;
2571  }
2572  }
2573 #endif
2574  }
2575  else if(memory_type == MEMORY_TYPE_ASYNCHRONOUS)
2576  {
2578  "---Applying memory correction for MEMORY_TYPE_ASYNCHRONOUS");
2579  unsigned var = get_memory_var(fu);
2580  if(!Rmem->is_a_proxied_variable(var))
2581  {
2582  is_proxied_correction = true;
2583  }
2584  if(Rmem->is_read_only_variable(var))
2585  {
2586  is_read_only_correction = true;
2587  }
2588  is_single_variable = single_var_lambda(var);
2589 
2590  const auto type_node = tree_helper::CGetType(TreeM->CGetTreeReindex(var));
2592 #if ARRAY_CORRECTION
2594  {
2595  const auto dims = tree_helper::GetArrayDimensions(type_node);
2596  unsigned int n_not_power_of_two = 0;
2597  for(auto idx : dims)
2598  if(idx & (idx - 1))
2599  ++n_not_power_of_two;
2600  if((dims.size() > 1 && n_not_power_of_two > 0))
2601  {
2602  const technology_managerRef TM = HLS_D->get_technology_manager();
2603  auto bus_addr_bitsize = resize_1_8_pow2(address_bitsize);
2604  technology_nodeRef f_unit =
2605  TM->get_fu(ADDER_STD + std::string("_" + STR(bus_addr_bitsize) + "_" + STR(bus_addr_bitsize) + "_" +
2606  STR(bus_addr_bitsize)),
2607  LIBRARY_STD_FU);
2608  THROW_ASSERT(f_unit, "Library miss component: " + std::string(ADDER_STD) +
2609  std::string("_" + STR(bus_addr_bitsize) + "_" + STR(bus_addr_bitsize) + "_" +
2610  STR(bus_addr_bitsize)));
2611  functional_unit* Fu = GetPointer<functional_unit>(f_unit);
2612  technology_nodeRef op_node = Fu->get_operation("plus_expr");
2613  operation* op = GetPointer<operation>(op_node);
2614  double delay = time_m_execution_time(op) - get_setup_hold_time();
2615  unsigned int n_levels = 0;
2616  for(; dims.size() >= (1u << n_levels); ++n_levels)
2617  ;
2618  res_value -= (n_levels - 1) * delay;
2619  }
2620  }
2621 #endif
2622  }
2623  else if(memory_type == MEMORY_TYPE_SYNCHRONOUS_SDS || memory_type == MEMORY_TYPE_SYNCHRONOUS_SDS_BUS)
2624  {
2626  DEBUG_LEVEL_VERY_PEDANTIC, debug_level,
2627  "---Applying memory correction for MEMORY_TYPE_SYNCHRONOUS_SDS and MEMORY_TYPE_SYNCHRONOUS_SDS_BUS");
2628  unsigned var = get_memory_var(fu);
2629  is_single_variable = single_var_lambda(var);
2630 
2631  const auto type_node = tree_helper::CGetType(TreeM->CGetTreeReindex(var));
2633 #if ARRAY_CORRECTION
2635  {
2636  const auto dims = tree_helper::GetArrayDimensions(type_node);
2637  unsigned int n_not_power_of_two = 0;
2638  for(auto idx : dims)
2639  if(idx & (idx - 1))
2640  ++n_not_power_of_two;
2641  if((dims.size() > 1 && n_not_power_of_two > 0))
2642  {
2643  const technology_managerRef TM = HLS_D->get_technology_manager();
2644  auto bus_addr_bitsize = resize_1_8_pow2(address_bitsize);
2645  technology_nodeRef f_unit =
2646  TM->get_fu(ADDER_STD + std::string("_" + STR(bus_addr_bitsize) + "_" + STR(bus_addr_bitsize) + "_" +
2647  STR(bus_addr_bitsize)),
2648  LIBRARY_STD_FU);
2649  THROW_ASSERT(f_unit, "Library miss component: " + std::string(ADDER_STD) +
2650  std::string("_" + STR(bus_addr_bitsize) + "_" + STR(bus_addr_bitsize) + "_" +
2651  STR(bus_addr_bitsize)));
2652  functional_unit* Fu = GetPointer<functional_unit>(f_unit);
2653  technology_nodeRef op_node = Fu->get_operation("plus_expr");
2654  operation* op = GetPointer<operation>(op_node);
2655  double delay = time_m_execution_time(op) - get_setup_hold_time();
2656  unsigned int n_levels = 0;
2657  for(; dims.size() >= (1u << n_levels); ++n_levels)
2658  ;
2659  res_value -= (n_levels - 1) * delay;
2660  }
2661  }
2662 #endif
2663  }
2664  else if(memory_ctrl_type == MEMORY_CTRL_TYPE_PROXY || memory_ctrl_type == MEMORY_CTRL_TYPE_PROXYN ||
2665  memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXY || memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXYN ||
2666  memory_ctrl_type == MEMORY_CTRL_TYPE_SPROXY || memory_ctrl_type == MEMORY_CTRL_TYPE_SPROXYN)
2667  {
2668  is_a_proxy = true;
2669  unsigned var = proxy_memory_units.find(fu)->second;
2671  "---Applying memory correction for PROXY for var:" + STR(var));
2672  if(Rmem->is_read_only_variable(var))
2673  {
2674  is_read_only_correction = true;
2675  }
2676  is_single_variable = single_var_lambda(var);
2677 
2678  auto* fu_cur = GetPointerS<functional_unit>(current_fu);
2679  technology_nodeRef op_cur_node = fu_cur->get_operation(operation_name);
2680  std::string latency_postfix =
2681  (memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXY || memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXYN) ?
2682  "" :
2683  get_latency_string(fu_cur->bram_load_latency);
2684 
2685  auto* op_cur = GetPointerS<operation>(op_cur_node);
2686  double cur_exec_time =
2687  op_cur->time_m->get_initiation_time() != 0u ? time_m_stage_period(op_cur) : time_m_execution_time(op_cur);
2688  double cur_exec_delta;
2689  technology_nodeRef f_unit_sds;
2690  if(Rmem->is_sds_var(var))
2691  {
2692  if(memory_ctrl_type == MEMORY_CTRL_TYPE_PROXY || memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXY ||
2693  memory_ctrl_type == MEMORY_CTRL_TYPE_SPROXY)
2694  {
2695  if(Rmem->is_private_memory(var))
2696  {
2697  if(memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXY)
2698  {
2699  f_unit_sds = HLS_D->get_technology_manager()->get_fu(ARRAY_1D_STD_DISTRAM_SDS, LIBRARY_STD_FU);
2700  }
2701  else
2702  {
2703  f_unit_sds =
2704  HLS_D->get_technology_manager()->get_fu(ARRAY_1D_STD_BRAM_SDS + latency_postfix, LIBRARY_STD_FU);
2705  }
2706  }
2707  else
2708  {
2709  f_unit_sds =
2710  HLS_D->get_technology_manager()->get_fu(ARRAY_1D_STD_BRAM_SDS_BUS + latency_postfix, LIBRARY_STD_FU);
2711  }
2712  }
2713  else
2714  {
2715  if(Rmem->is_private_memory(var))
2716  {
2717  if(memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXYN)
2718  {
2719  f_unit_sds = HLS_D->get_technology_manager()->get_fu(ARRAY_1D_STD_DISTRAM_NN_SDS, LIBRARY_STD_FU);
2720  }
2721  else
2722  {
2723  f_unit_sds = HLS_D->get_technology_manager()->get_fu(ARRAY_1D_STD_BRAM_NN_SDS + latency_postfix,
2724  LIBRARY_STD_FU);
2725  }
2726  }
2727  else
2728  {
2729  f_unit_sds = HLS_D->get_technology_manager()->get_fu(ARRAY_1D_STD_BRAM_NN_SDS_BUS + latency_postfix,
2730  LIBRARY_STD_FU);
2731  }
2732  }
2733 
2734  const auto type_node = tree_helper::CGetType(TreeM->CGetTreeReindex(var));
2736  }
2737  else
2738  {
2739  f_unit_sds = HLS_D->get_technology_manager()->get_fu(ARRAY_1D_STD_BRAM_NN + latency_postfix, LIBRARY_STD_FU);
2740  if(Rmem->is_private_memory(var))
2741  {
2742  is_private_correction = true;
2743  }
2744  elmt_bitsize = Rmem->get_bram_bitsize();
2745  }
2746  THROW_ASSERT(f_unit_sds, "Library miss component");
2747  auto* fu_sds = GetPointer<functional_unit>(f_unit_sds);
2748  technology_nodeRef op_sds_node = fu_sds->get_operation(operation_name);
2749  auto* op_sds = GetPointer<operation>(op_sds_node);
2750  double cur_sds_exec_time =
2751  op_sds->time_m->get_initiation_time() != 0u ? time_m_stage_period(op_sds) : time_m_execution_time(op_sds);
2752  cur_exec_delta = cur_exec_time - cur_sds_exec_time;
2753  res_value = res_value + cur_exec_delta;
2754 
2755 #if ARRAY_CORRECTION
2756  const auto type_node = tree_helper::CGetType(TreeM->CGetTreeReindex(var));
2758  {
2759  const auto dims = tree_helper::GetArrayDimensions(type_node);
2760  unsigned int n_not_power_of_two = 0;
2761  for(auto idx : dims)
2762  if(idx & (idx - 1))
2763  ++n_not_power_of_two;
2764  if(dims.size() > 1 && n_not_power_of_two > 0)
2765  {
2766  const technology_managerRef TM = HLS_D->get_technology_manager();
2767  auto bus_addr_bitsize = resize_1_8_pow2(address_bitsize);
2768  technology_nodeRef f_unit =
2769  TM->get_fu(ADDER_STD + std::string("_" + STR(bus_addr_bitsize) + "_" + STR(bus_addr_bitsize) + "_" +
2770  STR(bus_addr_bitsize)),
2771  LIBRARY_STD_FU);
2772  functional_unit* Fu = GetPointer<functional_unit>(f_unit);
2773  technology_nodeRef op_node = Fu->get_operation("plus_expr");
2774  operation* op = GetPointer<operation>(op_node);
2775  double delay = time_m_execution_time(op) - get_setup_hold_time();
2776  unsigned int n_levels = 0;
2777  for(; dims.size() >= (1u << n_levels); ++n_levels)
2778  ;
2779  res_value -= (n_levels - 1) * delay;
2780  }
2781  }
2782 #endif
2783  }
2784  else if(memory_ctrl_type == MEMORY_CTRL_TYPE_D00)
2785  {
2786  elmt_bitsize = Rmem->get_bram_bitsize();
2787  }
2788  else if(is_single_bool_test_cond_expr_units(fu))
2789  {
2790  auto prec = get_prec(fu);
2791  auto fu_prec = resize_1_8_pow2(prec);
2792  if(fu_prec > 1)
2793  {
2794  const technology_managerRef TM = HLS_D->get_technology_manager();
2795  auto true_delay = [&]() -> double {
2796  technology_nodeRef f_unit_ce = TM->get_fu(COND_EXPR_STD "_1_1_1_1", LIBRARY_STD_FU);
2797  auto* fu_ce = GetPointer<functional_unit>(f_unit_ce);
2798  technology_nodeRef op_ce_node = fu_ce->get_operation("cond_expr");
2799  auto* op_ce = GetPointer<operation>(op_ce_node);
2800  double setup_time = get_setup_hold_time();
2801  return time_m_execution_time(op_ce) - setup_time;
2802  }();
2803  technology_nodeRef f_unit_ce = TM->get_fu(get_fu_name(fu).first, LIBRARY_STD_FU);
2804  auto* fu_ce = GetPointer<functional_unit>(f_unit_ce);
2805  technology_nodeRef op_ce_node = fu_ce->get_operation("cond_expr");
2806  auto* op_ce = GetPointer<operation>(op_ce_node);
2807  double setup_time = get_setup_hold_time();
2808  double ce_delay = time_m_execution_time(op_ce) - setup_time;
2809  double correction = ce_delay - true_delay;
2810  res_value = res_value + correction;
2811  }
2812  }
2813  else if(is_simple_pointer_plus_expr(fu))
2814  {
2815  const technology_managerRef TM = HLS_D->get_technology_manager();
2816  technology_nodeRef f_unit_ce = TM->get_fu(get_fu_name(fu).first, LIBRARY_STD_FU);
2817  auto* fu_ce = GetPointer<functional_unit>(f_unit_ce);
2818  technology_nodeRef op_ce_node = fu_ce->get_operation(operation_name);
2819  auto* op_ce = GetPointer<operation>(op_ce_node);
2820  double setup_time = get_setup_hold_time();
2821  double ce_delay = time_m_execution_time(op_ce) - setup_time;
2822  double correction = ce_delay;
2823  res_value = res_value + correction;
2824  }
2825  else if(operation_name == "lut_expr")
2826  {
2827  // std::cerr << "get_correction_time " << operation_name << " - " << n_ins << "\n";
2828  if(HLS_D->has_parameter("max_lut_size") && HLS_D->get_parameter<size_t>("max_lut_size") != 0)
2829  {
2830  const technology_managerRef TM = HLS_D->get_technology_manager();
2832  auto* fu_lut = GetPointer<functional_unit>(f_unit_lut);
2833  technology_nodeRef op_lut_node = fu_lut->get_operation(operation_name);
2834  auto* op_lut = GetPointer<operation>(op_lut_node);
2835  double setup_time = get_setup_hold_time();
2836  double lut_delay = time_m_execution_time(op_lut) - setup_time;
2837  res_value = res_value + lut_delay;
2838  auto max_lut_size = HLS_D->get_parameter<size_t>("max_lut_size");
2839  if(n_ins > max_lut_size)
2840  {
2841  THROW_ERROR("unexpected condition");
2842  }
2843  else
2844  {
2845  auto delta_delay = (lut_delay * 1.) / static_cast<double>(max_lut_size);
2846  // std::cerr << "correction value = " << (max_lut_size-n_ins)*delta_delay << "\n";
2847  res_value = res_value - static_cast<double>(n_ins) * delta_delay;
2848  }
2849  }
2850  }
2851 
2853  "---Correction value after first correction " + STR(res_value));
2854  double bus_multiplier = 0;
2855  if(elmt_bitsize == 128)
2856  {
2857  bus_multiplier = -1.0;
2858  }
2859  else if(elmt_bitsize == 64)
2860  {
2861  bus_multiplier = -0.5;
2862  }
2863  else if(elmt_bitsize == 32)
2864  {
2865  bus_multiplier = 0;
2866  }
2867  else if(elmt_bitsize == 16)
2868  {
2869  bus_multiplier = +0;
2870  }
2871  else if(elmt_bitsize == 8)
2872  {
2873  bus_multiplier = +0;
2874  }
2875  res_value = res_value + bus_multiplier * (get_setup_hold_time() / time_multiplier);
2876  if(is_read_only_correction)
2877  {
2878  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Applying read only correction");
2879  res_value = res_value + memory_correction_coefficient * 0.5 * (get_setup_hold_time() / time_multiplier);
2880  }
2881  if(is_proxied_correction)
2882  {
2883  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Applying proxy correction");
2884  res_value =
2885  res_value + memory_correction_coefficient * (estimate_mux_time(fu) / (mux_time_multiplier * time_multiplier));
2886  }
2887  if(is_private_correction)
2888  {
2889  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Applying private correction");
2890  res_value =
2891  res_value + memory_correction_coefficient * (estimate_mux_time(fu) / (mux_time_multiplier * time_multiplier));
2892  }
2893  if(is_single_variable)
2894  {
2895  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Applying single variable correction");
2896  const technology_managerRef TM = HLS_D->get_technology_manager();
2897  auto fname = get_fu_name(fu).first;
2898  technology_nodeRef f_unit_sv = TM->get_fu(fname, TM->get_library(fname));
2899  auto* fu_sv = GetPointer<functional_unit>(f_unit_sv);
2900  technology_nodeRef op_sv_node = fu_sv->get_operation(operation_name);
2901  auto* op_sv = GetPointer<operation>(op_sv_node);
2902  double setup_time = get_setup_hold_time();
2903  double cur_sv_exec_time =
2904  op_sv->time_m->get_initiation_time() != 0u ? time_m_stage_period(op_sv) : time_m_execution_time(op_sv);
2905  if(is_a_proxy || is_proxied_correction)
2906  {
2907  res_value = cur_sv_exec_time - setup_time;
2908  }
2909  else
2910  {
2911  double sv_delay = cur_sv_exec_time - 2 * setup_time;
2912  double correction = sv_delay;
2913  res_value = res_value + correction;
2914  }
2915  }
2916  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Correction is " + STR(res_value));
2917  return res_value;
2918 }
2919 
2921 {
2922  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Estimating call delay");
2923  double clock_budget = HLS_C->get_clock_period_resource_fraction() * HLS_C->get_clock_period();
2924  double scheduling_mux_margins = parameters->getOption<double>(OPT_scheduling_mux_margins) * mux_time_unit(32);
2925  auto dfp_P =
2926  parameters->isOption(OPT_disable_function_proxy) && parameters->getOption<bool>(OPT_disable_function_proxy);
2927  double call_delay;
2928  if(!dfp_P)
2929  {
2930  call_delay = clock_budget;
2931  }
2932  else
2933  {
2934  call_delay = clock_budget;
2936  DEBUG_LEVEL_VERY_PEDANTIC, debug_level,
2937  "---Minimum slack " +
2938  STR(minimumSlack > 0.0 && minimumSlack != std::numeric_limits<double>::max() ? minimumSlack : 0));
2939  call_delay -= minimumSlack > 0.0 && minimumSlack != std::numeric_limits<double>::max() ? minimumSlack : 0;
2940  }
2941  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Call delay without slack " + STR(call_delay));
2942  if(call_delay < 0.0)
2943  {
2944  call_delay = get_setup_hold_time();
2945  }
2946  auto ctrl_delay = EstimateControllerDelay();
2947  if(call_delay < ctrl_delay)
2948  {
2949  call_delay = ctrl_delay;
2950  }
2952  std::string function_name = behavioral_helper->get_function_name();
2953  auto module_name = hls->top->get_circ()->get_typeRef()->id_type;
2954  auto* fu = GetPointer<functional_unit>(HLS_D->get_technology_manager()->get_fu(module_name, WORK_LIBRARY));
2955  auto* op = GetPointer<operation>(fu->get_operation(function_name));
2956  if(not op->bounded)
2957  {
2960  call_delay += EstimateControllerDelay();
2961  }
2962  if(call_delay >= clock_budget - scheduling_mux_margins)
2963  {
2964  call_delay = clock_budget - scheduling_mux_margins;
2965  }
2966  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Estimated call delay " + STR(call_delay));
2967  return call_delay;
2968 }
2969 
2970 double AllocationInformation::compute_normalized_area(unsigned int fu_s1) const
2971 {
2972  double mux_area = estimate_mux_area(fu_s1);
2973  double resource_area =
2974  is_single_bool_test_cond_expr_units(fu_s1) ? (mux_area > 1 ? (mux_area - 1) : 0) : get_area(fu_s1);
2975  if(resource_area > mux_area && resource_area - mux_area < 4)
2976  {
2977  resource_area = mux_area;
2978  }
2979  const auto fu_name = list_of_FU[fu_s1]->get_name();
2980  if(parameters->IsParameter("no-share-max") && parameters->GetParameter<int>("no-share-max") &&
2981  (fu_name.find("max_expr_FU_") != std::string::npos || fu_name.find("min_expr_FU_") != std::string::npos))
2982  {
2983  resource_area = 0.0;
2984  }
2985  return (resource_area / mux_area) + 3 * get_DSPs(fu_s1);
2986 }
2987 
2989 {
2990  return n_complex_operations;
2991 }
2992 
2993 std::string AllocationInformation::extract_bambu_provided_name(unsigned long long prec_in, unsigned long long prec_out,
2994  const HLS_managerConstRef hls_manager,
2995  technology_nodeRef& current_fu)
2996 {
2997  std::string unit_name;
2998  if(prec_in == 32 && prec_out == 64)
2999  {
3000  unit_name = SF_FFDATA_CONVERTER_32_64_STD;
3001  }
3002  else if(prec_in == 64 && prec_out == 32)
3003  {
3004  unit_name = SF_FFDATA_CONVERTER_64_32_STD;
3005  }
3006  else
3007  {
3008  THROW_ERROR("not supported float to float conversion: " + STR(prec_in) + " " + STR(prec_out));
3009  }
3010  current_fu = get_fu(unit_name, hls_manager);
3011  return unit_name;
3012 }
3013 
3014 bool AllocationInformation::has_constant_in(unsigned int fu_name) const
3015 {
3016  if(!has_to_be_synthetized(fu_name))
3017  {
3018  return false;
3019  }
3020  return GetPointer<functional_unit>(list_of_FU[fu_name])->characterizing_constant_value != "";
3021 }
3022 
3023 bool AllocationInformation::is_proxy_memory_unit(const unsigned int fu_name) const
3024 {
3025  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
3026  return proxy_memory_units.find(fu_name) != proxy_memory_units.end();
3027 }
3028 
3029 bool AllocationInformation::is_readonly_memory_unit(const unsigned int fu_name) const
3030 {
3031  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
3032  return (is_memory_unit(fu_name) && Rmem->is_read_only_variable(get_memory_var(fu_name))) ||
3033  (is_proxy_memory_unit(fu_name) && Rmem->is_read_only_variable(get_proxy_memory_var(fu_name)));
3034 }
3035 
3037 {
3038  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
3039  return single_bool_test_cond_expr_units.find(fu_name) != single_bool_test_cond_expr_units.end();
3040 }
3041 
3042 bool AllocationInformation::is_simple_pointer_plus_expr(const unsigned int fu_name) const
3043 {
3044  THROW_ASSERT(fu_name < get_number_fu_types(), "functional unit id not meaningful");
3045  return simple_pointer_plus_expr.find(fu_name) != simple_pointer_plus_expr.end();
3046 }
3047 
3048 unsigned int AllocationInformation::get_worst_number_of_cycles(const unsigned int fu_name) const
3049 {
3050  if(!has_to_be_synthetized(fu_name))
3051  {
3052  return 0;
3053  }
3054  const functional_unit::operation_vec node_ops = GetPointer<functional_unit>(list_of_FU[fu_name])->get_operations();
3055  unsigned int max_value = 0;
3056  auto no_it_end = node_ops.end();
3057  for(auto no_it = node_ops.begin(); no_it != no_it_end; ++no_it)
3058  {
3059  max_value = std::max(max_value, GetPointer<operation>(*no_it)->time_m->get_cycles());
3060  }
3061  return max_value;
3062 }
3063 
3065 {
3066  auto clock_period = HLS_C->get_clock_period();
3067  auto clock_period_resource_fraction = HLS_C->get_clock_period_resource_fraction();
3068  auto scheduling_mux_margins = parameters->getOption<double>(OPT_scheduling_mux_margins) * mux_time_unit(32);
3069  auto setup_hold_time = get_setup_hold_time();
3070 
3071  return clock_period - ((clock_period * clock_period_resource_fraction) - scheduling_mux_margins - setup_hold_time);
3072 }
3073 
3075 {
3076  const auto bb_version = hls_manager->CGetFunctionBehavior(function_index)->GetBBVersion();
3077  if(ssa_bb_versions.find(ssa) != ssa_bb_versions.end() &&
3078  ssa_bb_versions.find(ssa)->second == std::pair<unsigned int, AbsControlStep>(bb_version, cs))
3079  {
3081  "---Compute roots - Using cached values of " + STR(ssa) + " at version " + STR(bb_version));
3082  return ssa_roots.find(ssa)->second;
3083  }
3084  else
3085  {
3086  const auto schedule = hls->Rsch;
3087  CustomSet<unsigned int> already_analyzed_ssas;
3088  CustomSet<unsigned int> ssa_to_be_analyzeds;
3090  ssa_to_be_analyzeds.insert(ssa);
3092  "-->Computing roots of " + STR(ssa) + " at version " + STR(bb_version));
3093  while(ssa_to_be_analyzeds.size())
3094  {
3095  const auto current_tn_index = *(ssa_to_be_analyzeds.begin());
3096  ssa_to_be_analyzeds.erase(ssa_to_be_analyzeds.begin());
3097  if(already_analyzed_ssas.find(current_tn_index) != already_analyzed_ssas.end())
3098  {
3099  continue;
3100  }
3101  already_analyzed_ssas.insert(current_tn_index);
3103  "-->Considering " + STR(TreeM->CGetTreeNode(current_tn_index)));
3104  const auto current_sn = GetPointer<const ssa_name>(TreeM->CGetTreeNode(current_tn_index));
3105  if(not current_sn)
3106  {
3107  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Ignored since not ssa");
3108  continue;
3109  }
3110  const auto current_sn_def = current_sn->CGetDefStmt();
3111 #if 0
3112  if(schedule->is_scheduled(current_sn_def->index) && schedule->get_cstep(current_sn_def->index) != cs && cs.second != AbsControlStep::UNKNOWN)
3113  {
3114  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Ignored since defined in different control step " + STR(schedule->get_cstep(current_sn_def->index).second) + " vs. " + STR(cs.second));
3115  continue;
3116  }
3117 #endif
3118  if(cs.second == AbsControlStep::UNKNOWN &&
3119  cs.first != GetPointer<const gimple_node>(GET_NODE(current_sn_def))->bb_index)
3120  {
3121  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Ignored since defined in different basic block");
3122  continue;
3123  }
3124  const auto current_def_ga = GetPointer<const gimple_assign>(GET_NODE(current_sn_def));
3125  if(not current_def_ga)
3126  {
3127  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Adding as root " + current_sn->ToString());
3128  roots.insert(current_tn_index);
3129  continue;
3130  }
3131  const auto be = GetPointer<const binary_expr>(GET_NODE(current_def_ga->op1));
3132  if(be &&
3133  (be->get_kind() == rshift_expr_K || be->get_kind() == lshift_expr_K || be->get_kind() == bit_and_expr_K))
3134  {
3135  if(GET_NODE(be->op1)->get_kind() != integer_cst_K)
3136  {
3138  "<--Adding as root " + current_sn->ToString() +
3139  " which is defined in a shift by variable or in an and with a variable");
3140  roots.insert(current_tn_index);
3141  continue;
3142  }
3143  else
3144  {
3146  "<--Defined in a shift by constant or in an and with a constant");
3147  if(already_analyzed_ssas.find(be->op0->index) == already_analyzed_ssas.end())
3148  {
3149  ssa_to_be_analyzeds.insert(be->op0->index);
3150  }
3151  continue;
3152  }
3153  }
3154  if(be && (be->get_kind() == gt_expr_K || be->get_kind() == ge_expr_K || be->get_kind() == lt_expr_K ||
3155  be->get_kind() == le_expr_K || be->get_kind() == eq_expr_K || be->get_kind() == ne_expr_K ||
3156  be->get_kind() == truth_and_expr_K || be->get_kind() == truth_or_expr_K ||
3157  be->get_kind() == truth_xor_expr_K))
3158  {
3159  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Defined in a comparison");
3160  if(already_analyzed_ssas.find(be->op0->index) == already_analyzed_ssas.end())
3161  {
3162  ssa_to_be_analyzeds.insert(be->op0->index);
3163  }
3164  if(already_analyzed_ssas.find(be->op1->index) == already_analyzed_ssas.end())
3165  {
3166  ssa_to_be_analyzeds.insert(be->op1->index);
3167  }
3168  continue;
3169  }
3170  const auto ue = GetPointer<const unary_expr>(GET_NODE(current_def_ga->op1));
3171  if(ue && (ue->get_kind() == truth_not_expr_K || ue->get_kind() == nop_expr_K))
3172  {
3173  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Defined in not or nop");
3174  if(already_analyzed_ssas.find(ue->op->index) == already_analyzed_ssas.end())
3175  {
3176  ssa_to_be_analyzeds.insert(ue->op->index);
3177  }
3178  continue;
3179  }
3180  const auto ce = GetPointer<const cond_expr>(GET_NODE(current_def_ga->op1));
3181  if(ce)
3182  {
3183  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Defined in cond expr");
3184  if(already_analyzed_ssas.find(ce->op0->index) == already_analyzed_ssas.end())
3185  {
3186  ssa_to_be_analyzeds.insert(ce->op0->index);
3187  }
3188  if(already_analyzed_ssas.find(ce->op1->index) == already_analyzed_ssas.end())
3189  {
3190  ssa_to_be_analyzeds.insert(ce->op1->index);
3191  }
3192  if(already_analyzed_ssas.find(ce->op2->index) == already_analyzed_ssas.end())
3193  {
3194  ssa_to_be_analyzeds.insert(ce->op2->index);
3195  }
3196  continue;
3197  }
3198  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Adding as root " + current_sn->ToString());
3199  roots.insert(current_tn_index);
3200  }
3201  ssa_bb_versions[ssa] = std::pair<unsigned int, AbsControlStep>(bb_version, cs);
3202  ssa_roots[ssa] = roots;
3204  "<--Computed roots of " + STR(ssa) + " at version " + STR(bb_version) + ": " + STR(roots.size()) +
3205  " elements");
3206  return roots;
3207  }
3208 }
3209 
3211 {
3212  const auto bb_version = hls_manager->CGetFunctionBehavior(function_index)->GetBBVersion();
3213  if(cond_expr_bb_versions.find(ssa) != cond_expr_bb_versions.end() &&
3214  cond_expr_bb_versions.find(ssa)->second == bb_version)
3215  {
3217  "---Computing cond_exprs starting from " + STR(TreeM->CGetTreeNode(ssa)) +
3218  " - Using cached values");
3219  return ssa_cond_exprs.find(ssa)->second;
3220  }
3221  else
3222  {
3224  "-->Computing cond_exprs starting from " + STR(TreeM->CGetTreeNode(ssa)));
3225  CustomSet<unsigned int> cond_expr_ga_indices;
3226  CustomSet<unsigned int> ssa_to_be_analyzeds;
3227  CustomSet<unsigned int> already_analyzed_ssas;
3228  ssa_to_be_analyzeds.insert(ssa);
3229  while(ssa_to_be_analyzeds.size())
3230  {
3231  const auto current_tn_index = *(ssa_to_be_analyzeds.begin());
3232  ssa_to_be_analyzeds.erase(ssa_to_be_analyzeds.begin());
3234  "-->Considering " + STR(TreeM->CGetTreeNode(current_tn_index)));
3235  const auto current_sn = GetPointer<const ssa_name>(TreeM->CGetTreeNode(current_tn_index));
3236  if(!current_sn)
3237  {
3238  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Ignored since not ssa");
3239  continue;
3240  }
3241  for(const auto& use_stmt : current_sn->CGetUseStmts())
3242  {
3243  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Considering use in " + STR(use_stmt.first));
3244  if(GET_NODE(use_stmt.first)->get_kind() != gimple_assign_K)
3245  {
3246  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Skipping since not gimple assignment");
3247  continue;
3248  }
3249  const auto current_use_ga = GetPointer<const gimple_assign>(GET_NODE(use_stmt.first));
3250  const auto be = GetPointer<const binary_expr>(GET_NODE(current_use_ga->op1));
3251  if(be &&
3252  (be->get_kind() == rshift_expr_K || be->get_kind() == lshift_expr_K || be->get_kind() == bit_and_expr_K))
3253  {
3254  if(GET_NODE(be->op1)->get_kind() != integer_cst_K)
3255  {
3257  "<--Used in a shift by a variable or in an and with a variable");
3258  continue;
3259  }
3260  else
3261  {
3263  "<--Used in a shift by constant or in an and with a constant");
3264  if(already_analyzed_ssas.find(current_use_ga->op0->index) == already_analyzed_ssas.end())
3265  {
3266  ssa_to_be_analyzeds.insert(current_use_ga->op0->index);
3267  }
3268  continue;
3269  }
3270  }
3271  if(be && (be->get_kind() == gt_expr_K || be->get_kind() == ge_expr_K || be->get_kind() == lt_expr_K ||
3272  be->get_kind() == le_expr_K || be->get_kind() == eq_expr_K || be->get_kind() == ne_expr_K ||
3273  be->get_kind() == truth_and_expr_K || be->get_kind() == truth_or_expr_K ||
3274  be->get_kind() == truth_xor_expr_K))
3275  {
3276  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Used in a comparison");
3277  if(already_analyzed_ssas.find(current_use_ga->op0->index) == already_analyzed_ssas.end())
3278  {
3279  ssa_to_be_analyzeds.insert(current_use_ga->op0->index);
3280  }
3281  continue;
3282  }
3283  const auto ue = GetPointer<const unary_expr>(GET_NODE(current_use_ga->op1));
3284  if(ue && ue->get_kind() == truth_not_expr_K)
3285  {
3286  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Used in not");
3287  if(already_analyzed_ssas.find(current_use_ga->op0->index) == already_analyzed_ssas.end())
3288  {
3289  ssa_to_be_analyzeds.insert(current_use_ga->op0->index);
3290  }
3291  continue;
3292  }
3293  if(ue && ue->get_kind() == nop_expr_K)
3294  {
3295  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Used in nop");
3296  if(already_analyzed_ssas.find(current_use_ga->op0->index) == already_analyzed_ssas.end())
3297  {
3298  ssa_to_be_analyzeds.insert(current_use_ga->op0->index);
3299  }
3300  continue;
3301  }
3302  if(GET_NODE(current_use_ga->op1)->get_kind() == cond_expr_K)
3303  {
3304  const auto ce = GetPointer<const cond_expr>(GET_NODE(current_use_ga->op1));
3305  if(ce->op0->index != current_tn_index)
3306  {
3308  "<--Used as operand of a cond_expr, but not as condition");
3309  continue;
3310  }
3311  cond_expr_ga_indices.insert(current_use_ga->index);
3312  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Adding cond expr " + STR(current_use_ga));
3313  continue;
3314  }
3315  else
3316  {
3317  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Skipping");
3318  continue;
3319  }
3320  }
3322  "<--Considered " + STR(TreeM->CGetTreeNode(current_tn_index)));
3323  }
3324  cond_expr_bb_versions[ssa] = bb_version;
3325  ssa_cond_exprs[ssa] = cond_expr_ga_indices;
3327  "<--Computed cond_exprs starting from " + STR(TreeM->CGetTreeNode(ssa)));
3328  return cond_expr_ga_indices;
3329  }
3330 }
3331 
3332 double AllocationInformation::GetConnectionTime(const vertex first_operation, const vertex second_operation,
3333  const AbsControlStep cs) const
3334 {
3335  const auto first_operation_index = op_graph->CGetOpNodeInfo(first_operation)->GetNodeId();
3336  const auto second_operation_index = second_operation ? op_graph->CGetOpNodeInfo(second_operation)->GetNodeId() : 0;
3337  return GetConnectionTime(first_operation_index, second_operation_index, cs);
3338 }
3339 
3340 double AllocationInformation::GetConnectionTime(const unsigned int first_operation, const unsigned int second_operation,
3341  const AbsControlStep cs) const
3342 {
3343  if(!parameters->getOption<bool>(OPT_estimate_logic_and_connections))
3344  {
3345  return 0;
3346  }
3347  if(second_operation == 0)
3348  {
3349  if(first_operation == ENTRY_ID || first_operation == EXIT_ID)
3350  {
3351  return 0.0;
3352  }
3353  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Get end delay of " + STR(first_operation));
3354  double end_delay = 0.0;
3355  const auto first_operation_tn = TreeM->CGetTreeNode(first_operation);
3356  if(GetPointer<const gimple_multi_way_if>(first_operation_tn) ||
3357  GetPointer<const gimple_switch>(first_operation_tn) || GetPointer<const gimple_cond>(first_operation_tn))
3358  {
3359  end_delay = estimate_controller_delay_fb();
3360  }
3361  else
3362  {
3363  double phi_delay = GetPhiConnectionLatency(first_operation);
3364  if(phi_delay > end_delay)
3365  {
3366  end_delay = phi_delay;
3367  }
3368  double to_dsp_register_delay = GetToDspRegisterDelay(first_operation);
3369  if(to_dsp_register_delay > end_delay)
3370  {
3371  end_delay = to_dsp_register_delay;
3372  }
3373  }
3375  "<--Got end delay of " + STR(first_operation) + ": " + STR(end_delay));
3376  return end_delay;
3377  }
3378  if(is_operation_PI_registered(second_operation))
3379  {
3381  "-->Computing overall connection time " + STR(first_operation) + "-->" + STR(second_operation) +
3382  " Second operation has registered inputs");
3383  const auto second_operation_tn = TreeM->CGetTreeNode(second_operation);
3384  const auto second_operation_name = GetPointer<const gimple_node>(second_operation_tn)->operation;
3385  const auto called_function = TreeM->GetFunction(second_operation_name);
3386  THROW_ASSERT(called_function, STR(second_operation_tn) + " has registered inputs but it is not a call");
3387  const auto called_hls = hls_manager->get_HLS(called_function->index);
3388  const auto called_sites_number = called_hls->call_sites_number;
3389 
3390  double mux_delay = 0.0;
3391  unsigned int n_levels = 0;
3392  for(; called_sites_number > (1u << n_levels); ++n_levels)
3393  {
3394  ;
3395  }
3396  mux_delay = (n_levels * mux_time_unit(32));
3398  "<--Got connection time " + STR(first_operation) + "-->" + STR(second_operation) + ": " +
3399  STR(mux_delay));
3400  return mux_delay;
3401  }
3402  else if(first_operation != ENTRY_ID && first_operation != EXIT_ID && second_operation != ENTRY_ID &&
3403  second_operation != EXIT_ID &&
3404  (behavioral_helper->IsLut(first_operation) || behavioral_helper->IsLut(second_operation)))
3405  {
3406  return 0;
3407  }
3408  else
3409  {
3410  const auto second_operation_tn = TreeM->CGetTreeNode(second_operation);
3411  tree_nodeRef cond_def;
3412 
3413  double connection_time = 0.0;
3415  "-->Computing overall connection time " + STR(first_operation) + "-->" + STR(second_operation));
3416 
3418  "-->Computing connection time due to fanout " + STR(first_operation) + "-->" +
3419  STR(second_operation));
3420  for(const auto& used_ssa : tree_helper::ComputeSsaUses(TreeM->CGetTreeReindex(second_operation)))
3421  {
3422  const auto used_ssa_sn = GetPointer<const ssa_name>(GET_NODE(used_ssa.first));
3423  if(used_ssa_sn && used_ssa_sn->CGetDefStmt()->index == first_operation)
3424  {
3425  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Transferred data is " + STR(used_ssa.first));
3426  const auto roots = ComputeRoots(used_ssa_sn->index, cs);
3427  if(roots.find(used_ssa_sn->index) != roots.end())
3428  {
3429  CustomSet<unsigned int> cond_expr_ga_indices;
3430  const auto this_cond_expr = ComputeDrivenCondExpr(used_ssa_sn->index);
3431  cond_expr_ga_indices.insert(this_cond_expr.begin(), this_cond_expr.end());
3432 
3433  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Computing fan out");
3434  size_t n_fo = 0;
3435  for(const auto cond_expr_ga_index : cond_expr_ga_indices)
3436  {
3437  const auto current_ga = GetPointer<const gimple_assign>(TreeM->CGetTreeNode(cond_expr_ga_index));
3438  const auto cond_def_sn = GetPointer<const ssa_name>(GET_NODE(current_ga->op0));
3439  const auto local_fo = tree_helper::Size(current_ga->op0) * cond_def_sn->CGetNumberUses();
3441  "---Incrementing fan out of " + STR(local_fo) + " because of " +
3442  STR(TreeM->CGetTreeNode(cond_expr_ga_index)));
3443  n_fo += local_fo;
3444  }
3446  "<--Estimated FO of " + STR(first_operation) + "-->" + STR(second_operation) + " = " +
3447  STR(n_fo));
3448  if(n_fo)
3449  {
3450  double fo_correction = fanout_coefficient * get_setup_hold_time() * static_cast<double>(n_fo);
3451  if(fo_correction < connection_offset)
3452  {
3453  fo_correction = connection_offset;
3454  }
3455  else if(fo_correction > 1.1 * (connection_offset + get_setup_hold_time()))
3456  {
3457  fo_correction = 1.1 * (connection_offset + get_setup_hold_time());
3458  }
3460  "---Computed connection time due to fanout " + STR(first_operation) + "-->" +
3461  STR(second_operation) + ": " + STR(fo_correction));
3462  connection_time += fo_correction;
3463  }
3464  else
3465  {
3467  "---Computed connection time due to fanout" + STR(first_operation) + "-->" +
3468  STR(second_operation) + ": 0.0");
3469  }
3470  }
3471  }
3472  else
3473  {
3475  "---Input data (coming from other operation) is " + STR(used_ssa.first));
3476  }
3477  }
3478  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--");
3479  const bool is_load_store =
3480  behavioral_helper->IsLoad(second_operation) || behavioral_helper->IsStore(second_operation);
3481  if(is_load_store)
3482  {
3484  "-->Computing connection time for load and store" + STR(first_operation) + "-->" +
3485  STR(second_operation));
3486  const auto fu_type = GetFuType(second_operation);
3487  bool is_array = is_direct_access_memory_unit(fu_type);
3488  unsigned var =
3489  is_array ? (is_memory_unit(fu_type) ? get_memory_var(fu_type) : get_proxy_memory_var(fu_type)) : 0;
3490  auto nchannels = get_number_channels(fu_type);
3491  if(var && hls_manager->Rmem->get_maximum_references(var) > (2 * nchannels))
3492  {
3493  if(nchannels == 0)
3494  {
3495  THROW_ERROR("nchannels should be different than zero");
3496  }
3497  const auto ret = estimate_muxNto1_delay(
3498  get_prec(fu_type),
3499  static_cast<unsigned int>(hls_manager->Rmem->get_maximum_references(var)) / (2 * nchannels));
3500  connection_time += ret;
3501  }
3503  "<--Computed connection time for load and store " + STR(first_operation) + "-->" +
3504  STR(second_operation) + ": 0.0");
3505  }
3506  if(first_operation != ENTRY_ID)
3507  {
3508  const auto first_operation_tn = TreeM->CGetTreeNode(first_operation);
3509  const bool is_first_load = behavioral_helper->IsLoad(first_operation);
3510  if(is_first_load)
3511  {
3513  "-->Computing connection time of load " + STR(first_operation) + "-->" +
3514  STR(second_operation));
3515  const auto fu_type = GetFuType(first_operation);
3516  bool is_array = is_direct_access_memory_unit(fu_type);
3517  unsigned var =
3518  is_array ? (is_memory_unit(fu_type) ? get_memory_var(fu_type) : get_proxy_memory_var(fu_type)) : 0;
3519  auto nchannels = get_number_channels(fu_type);
3520  if(var && hls_manager->Rmem->get_maximum_loads(var) > (nchannels))
3521  {
3522  if(nchannels == 0)
3523  {
3524  THROW_ERROR("nchannels should be different than zero");
3525  }
3526  auto ret = estimate_muxNto1_delay(get_prec(fu_type),
3527  static_cast<unsigned int>(hls_manager->Rmem->get_maximum_loads(var)) /
3528  (nchannels));
3529  if(ret > (2.5 * get_setup_hold_time()))
3530  {
3531  ret = 2.5 * get_setup_hold_time();
3532  }
3534  "<--Computed connection time of load " + STR(first_operation) + "-->" +
3535  STR(second_operation) + ": " + STR(ret) + " var=" + STR(var));
3536  connection_time += ret;
3537  }
3538  else
3539  {
3541  "<--Computed connection time of load " + STR(first_operation) + "-->" +
3542  STR(second_operation) + ": 0.0");
3543  }
3544  }
3545  else if(GetPointer<const gimple_node>(first_operation_tn)->operation != "STORE")
3546  {
3547  if(CanImplementSetNotEmpty(first_operation))
3548  {
3549  const auto fu_type = GetFuType(first_operation);
3550  const auto n_resources = get_number_fu(fu_type);
3551  if(n_resources != INFINITE_UINT)
3552  {
3553  auto ret = estimate_muxNto1_delay(get_prec(fu_type), max_number_of_operations(fu_type) / n_resources);
3554  if(ret != 0.0)
3555  {
3556  connection_time += ret;
3557  }
3558  }
3559  }
3560  }
3561  }
3562  if(first_operation != ENTRY_ID && TreeM->CGetTreeNode(first_operation)->get_kind() == gimple_assign_K)
3563  {
3564  const auto first_operation_tn = TreeM->CGetTreeNode(first_operation);
3565  const auto ga = GetPointer<const gimple_assign>(first_operation_tn);
3566  const auto ne = GetPointer<const nop_expr>(GET_CONST_NODE(ga->op1));
3567  if(ne)
3568  {
3569  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Computing connection time due to conversion");
3570  const auto bool_input_ne = tree_helper::is_int(TreeM, ne->op->index);
3571  // cppcheck-suppress variableScope
3572  double fo_correction = 0.0;
3573  // cppcheck-suppress variableScope
3574  size_t fanout = 0;
3575  if(bool_input_ne)
3576  {
3577  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Not expr with signed input in right part");
3578  const auto output_sn =
3579  GetPointer<const ssa_name>(GET_CONST_NODE(GetPointer<const gimple_assign>(first_operation_tn)->op0));
3580  const auto input_sn = GetPointer<const ssa_name>(GET_CONST_NODE(ne->op));
3581  if(output_sn && input_sn && tree_helper::Size(ga->op0) > tree_helper::Size(ne->op))
3582  {
3583  fanout = (tree_helper::Size(ga->op0) - tree_helper::Size(ne->op) + 1) * output_sn->CGetNumberUses();
3584  fo_correction = fanout_coefficient * get_setup_hold_time() * static_cast<double>(fanout);
3585  if(fo_correction < connection_offset)
3586  {
3587  fo_correction = connection_offset;
3588  }
3589  else if(fo_correction > 1.1 * (connection_offset + get_setup_hold_time()))
3590  {
3591  fo_correction = 1.1 * (connection_offset + get_setup_hold_time());
3592  }
3593  connection_time += fo_correction;
3594  }
3595  }
3597  "<--Computed connection time due to conversion " + STR(first_operation) + "-->" +
3598  STR(second_operation) + "(fanout " + STR(fanout) + ") : " + STR(fo_correction));
3599  }
3600  }
3601  if(CanImplementSetNotEmpty(first_operation) && get_DSPs(GetFuType(first_operation)) != 0.0)
3602  {
3603  connection_time += output_DSP_connection_time;
3605  "---Connection time due to DSP connection " + STR(output_DSP_connection_time));
3606  }
3607  if(first_operation != ENTRY_ID && TreeM->CGetTreeNode(first_operation)->get_kind() == gimple_assign_K)
3608  {
3609  const auto first_operation_tn = TreeM->CGetTreeNode(first_operation);
3610  const auto op1_kind = GET_CONST_NODE(GetPointer<const gimple_assign>(first_operation_tn)->op1)->get_kind();
3611  if(op1_kind == plus_expr_K || op1_kind == minus_expr_K || op1_kind == ternary_plus_expr_K ||
3612  op1_kind == ternary_pm_expr_K || op1_kind == ternary_mp_expr_K || op1_kind == ternary_mm_expr_K ||
3613  op1_kind == eq_expr_K || op1_kind == ne_expr_K || op1_kind == gt_expr_K || op1_kind == ge_expr_K ||
3614  op1_kind == lt_expr_K || op1_kind == le_expr_K || op1_kind == pointer_plus_expr_K)
3615  {
3616  const bool adding_connection = [&]() -> bool {
3617  const auto second_delay = GetTimeLatency(second_operation, fu_binding::UNKNOWN);
3618  if(second_delay.first > epsilon)
3619  {
3620  return true;
3621  }
3622  const auto first_bb_index =
3623  GetPointer<const gimple_assign>(TreeM->CGetTreeNode(first_operation))->bb_index;
3624  const auto zero_distance_operations = GetZeroDistanceOperations(second_operation);
3625  for(const auto zero_distance_operation : zero_distance_operations)
3626  {
3627  if(GetPointer<const gimple_node>(TreeM->CGetTreeNode(zero_distance_operation))->bb_index ==
3628  first_bb_index)
3629  {
3630  const auto other_delay = GetTimeLatency(zero_distance_operation, fu_binding::UNKNOWN);
3631  if(other_delay.first > epsilon || other_delay.second > epsilon)
3632  {
3633  return true;
3634  }
3635  }
3636  }
3637  return false;
3638  }();
3639  if(adding_connection)
3640  {
3641  connection_time += output_carry_connection_time;
3643  "---Connection time due to carry connection " + STR(output_carry_connection_time));
3644  }
3645  }
3646  }
3647 #if 0
3648  if(CanImplementSetNotEmpty(first_operation) && is_indirect_access_memory_unit(GetFuType(first_operation)))
3650  {
3651  const auto bus_delay = get_setup_hold_time() * 2.5;
3652  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Bus delay is " + STR(bus_delay));
3653  connection_time += bus_delay;
3654  }
3655 #endif
3656 #if 0
3657  const bool is_second_ternary_plus =
3658  GetPointer<const gimple_node>(second_operation_tn)->operation == "ternary_plus_expr" ||
3659  GetPointer<const gimple_node>(second_operation_tn)->operation == "ternary_pm_expr" ||
3660  GetPointer<const gimple_node>(second_operation_tn)->operation == "ternary_mp_expr" ||
3661  GetPointer<const gimple_node>(second_operation_tn)->operation == "ternary_mm_expr";
3662  if(is_second_ternary_plus)
3663  {
3664  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Computing connection time " + STR(first_operation) + "-->" + STR(second_operation));
3665  auto ret = get_setup_hold_time()/3;
3666  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Computed connection time " + STR(first_operation) + "-->" + STR(second_operation) + ": " + STR(ret));
3667  return ret;
3668  }
3669  const bool is_second_plus_minus = GetPointer<const gimple_node>(second_operation_tn)->operation == "plus_expr" || GetPointer<const gimple_node>(second_operation_tn)->operation == "minus_expr";
3670  if(is_second_plus_minus)
3671  {
3672  const auto fu_type = GetFuType(second_operation);
3673  if(get_prec(fu_type) > 32)
3674  {
3675  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Computing connection time " + STR(first_operation) + "-->" + STR(second_operation));
3676  auto ret = get_setup_hold_time()/3;
3677  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Computed connection time " + STR(first_operation) + "-->" + STR(second_operation) + ": " + STR(ret));
3678  return ret;
3679  }
3680  }
3681 #endif
3682  if(!CanBeMerged(first_operation, second_operation))
3683  {
3684  connection_time = std::max(connection_time, connection_offset);
3685  }
3686 
3688  "<--Computed overall connection time " + STR(first_operation) + "-->" + STR(second_operation) +
3689  ": " + STR(connection_time));
3690  return connection_time;
3691  }
3692 }
3693 
3694 bool AllocationInformation::can_be_asynchronous_ram(tree_managerConstRef TM, unsigned int var, unsigned int threshold,
3695  bool is_read_only_variable, unsigned channel_number)
3696 {
3697  tree_nodeRef var_node = TM->get_tree_node_const(var);
3698  auto* vd = GetPointer<const var_decl>(var_node);
3699  auto var_bitsize = tree_helper::Size(var_node);
3700  const auto hls_d = hls_manager->get_HLS_device();
3701  if(is_read_only_variable)
3702  {
3703  threshold = 32 * threshold;
3704  }
3705  else if(hls_d->has_parameter("max_distram_nn_size") && channel_number > 1)
3706  {
3707  threshold = hls_d->get_parameter<unsigned int>("max_distram_nn_size");
3708  }
3709  if(vd)
3710  {
3711  const auto array_type_node = tree_helper::CGetType(var_node);
3712  if(GetPointer<const array_type>(GET_CONST_NODE(array_type_node)))
3713  {
3714  std::vector<unsigned long long> dims;
3715  unsigned long long elts_size;
3716  tree_helper::get_array_dim_and_bitsize(TM, array_type_node->index, dims, elts_size);
3717  unsigned long long meaningful_bits = 0;
3718  if(vd->bit_values.size() != 0)
3719  {
3720  for(auto bit_el : vd->bit_values)
3721  {
3722  if(bit_el == 'U')
3723  {
3724  ++meaningful_bits;
3725  }
3726  }
3727  }
3728  else
3729  {
3730  meaningful_bits = elts_size;
3731  }
3732  if(elts_size == 0)
3733  {
3734  THROW_ERROR("elts_size cannot be equal to zero");
3735  }
3736  if(meaningful_bits != elts_size)
3737  {
3738  auto real_bitsize = (var_bitsize / elts_size) * meaningful_bits;
3739  return (real_bitsize <= threshold) || (((var_bitsize / elts_size) <= 64) && channel_number == 1);
3740  }
3741  else
3742  {
3743  return (var_bitsize <= threshold) || (((var_bitsize / elts_size) <= 64) && channel_number == 1);
3744  }
3745  }
3746  else
3747  {
3748  return var_bitsize <= threshold;
3749  }
3750  }
3751  else
3752  {
3753  return var_bitsize <= threshold;
3754  }
3755 }
3756 
3758 {
3759 #if 1
3760  return false;
3761 #else
3762  if(operation == ENTRY_ID || operation == EXIT_ID)
3763  {
3764  return false;
3765  }
3766  else if(GetPointer<const gimple_node>(TreeM->CGetTreeNode(operation))->operation == LOAD)
3767  {
3768  return true;
3769  }
3770  else if(CanImplementSetNotEmpty(operation))
3771  {
3772  for(const auto candidate_functional_unit : can_implement_set(operation))
3773  {
3774  if(get_DSPs(candidate_functional_unit))
3775  {
3776  return true;
3777  }
3778  }
3779  }
3780  return false;
3781 #endif
3782 }
3783 
3784 ControlStep AllocationInformation::op_et_to_cycles(double et, double clock_period) const
3785 {
3786  return ControlStep(static_cast<unsigned int>(ceil(et / clock_period)));
3787 }
3788 
3789 bool AllocationInformation::CanBeMerged(const unsigned int first_operation, const unsigned int second_operation) const
3790 {
3791  if(first_operation == ENTRY_ID || second_operation == EXIT_ID)
3792  {
3793  return true;
3794  }
3796  "-->Checking if " + STR(TreeM->CGetTreeNode(first_operation)) + " can be fused in " +
3797  STR(TreeM->CGetTreeNode(second_operation)));
3798  // const auto first_delay = GetTimeLatency(first_operation, fu_binding::UNKNOWN);
3799  const auto second_delay = GetTimeLatency(second_operation, fu_binding::UNKNOWN);
3800  if(/*(first_delay.first <= epsilon and first_delay.second <= epsilon) || */ (second_delay.first <= epsilon &&
3801  second_delay.second <= epsilon))
3802  {
3803  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Yes because one of the operations has zero delay");
3804  return true;
3805  }
3806  const auto ga0 = GetPointer<const gimple_assign>(TreeM->CGetTreeNode(first_operation));
3807  const auto ga1 = GetPointer<const gimple_assign>(TreeM->CGetTreeNode(second_operation));
3808 #if 0
3809  if(ga0 && tree_helper::Size(ga0->op0) == 1 && ga1 && tree_helper::Size(ga1->op1) == 1 && (!CanImplementSetNotEmpty(second_operation) || get_DSPs(GetFuType(second_operation)) == 0.0) && ga0->operation != "plus_expr" && ga0->operation != "minus_expr" && ga0->operation != "ternary_plus_expr" && ga0->operation != "ternary_mm_expr" && ga0->operation != "ternary_mp_expr" && ga0->operation != "ternary_pm_expr")
3810 #endif
3811 
3812  if(ga0 && tree_helper::Size(ga0->op0) == 1 && ga1 && tree_helper::Size(ga1->op1) == 1 &&
3813  (!CanImplementSetNotEmpty(second_operation) || get_DSPs(GetFuType(second_operation)) == 0.0))
3814  {
3815  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Yes because single bit");
3816  return true;
3817  }
3818  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--No");
3819  return false;
3820 }
3821 
3822 bool AllocationInformation::CanBeChained(const vertex first_statement, const vertex second_statement) const
3823 {
3824  const auto first_statement_index = op_graph->CGetOpNodeInfo(first_statement)->GetNodeId();
3825  const auto second_statement_index = op_graph->CGetOpNodeInfo(second_statement)->GetNodeId();
3826  const auto ret = CanBeChained(first_statement_index, second_statement_index);
3827  return ret;
3828 }
3829 
3830 bool AllocationInformation::CanBeChained(const unsigned int first_statement_index,
3831  const unsigned int second_statement_index) const
3832 {
3833  if(first_statement_index == ENTRY_ID || first_statement_index == EXIT_ID || second_statement_index == ENTRY_ID ||
3834  second_statement_index == EXIT_ID)
3835  {
3836  return true;
3837  }
3838  const auto first_tree_node = TreeM->CGetTreeNode(first_statement_index);
3839  const auto second_tree_node = TreeM->CGetTreeNode(second_statement_index);
3841  "-->Checking if (" + STR(second_statement_index) + ") " + STR(second_tree_node) +
3842  " can be chained with (" + STR(first_statement_index) + ") " + STR(first_tree_node));
3843  auto first_store = behavioral_helper->IsStore(first_statement_index);
3844  if(first_store)
3845  {
3846  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--No because first is a store");
3847  return false;
3848  }
3849  if(not is_operation_bounded(first_statement_index))
3850  {
3851  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--No because first is unbounded");
3852  return false;
3853  }
3854  auto second_load = behavioral_helper->IsLoad(second_statement_index);
3856  if(GetTimeLatency(
3857  first_statement_index,
3858  CanImplementSetNotEmpty(first_statement_index) ? GetFuType(first_statement_index) : fu_binding::UNKNOWN, 0)
3859  .first > 0.001 &&
3860  second_load && is_one_cycle_direct_access_memory_unit(GetFuType(second_statement_index)) &&
3861  (!is_readonly_memory_unit(GetFuType(second_statement_index)) ||
3862  (!parameters->isOption(OPT_rom_duplication) || !parameters->getOption<bool>(OPT_rom_duplication))) &&
3863  ((Rmem->get_maximum_references(is_memory_unit(GetFuType(second_statement_index)) ?
3864  get_memory_var(GetFuType(second_statement_index)) :
3865  get_proxy_memory_var(GetFuType(second_statement_index)))) >
3866  get_number_channels(GetFuType(second_statement_index))))
3867  {
3868  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--No because second is a load from distributed memory");
3869  return false;
3870  }
3871  auto first_type = first_tree_node->get_kind();
3872  auto second_store = behavioral_helper->IsStore(second_statement_index);
3874  if((first_type == gimple_cond_K || first_type == gimple_multi_way_if_K) && second_store)
3875  {
3877  DEBUG_LEVEL_VERY_PEDANTIC, debug_level,
3878  "<--No because stores cannot be executed in the same clock cycle of the condition which controls it");
3879  return false;
3880  }
3882  if((first_type == gimple_cond_K || first_type == gimple_multi_way_if_K) &&
3883  !is_operation_bounded(second_statement_index))
3884  {
3886  "<--No because unbounded operations cannot be executed in the same clock cycle of the condition "
3887  "which controls it");
3888  return false;
3889  }
3891  if((first_type == gimple_cond_K || first_type == gimple_multi_way_if_K) &&
3892  (second_tree_node->get_kind() == gimple_label_K))
3893  {
3895  "<--No because labels and nops cannot be executed in the same clock cycle of the condition which "
3896  "controls it");
3897  return false;
3898  }
3900  if((first_type == gimple_cond_K || first_type == gimple_multi_way_if_K) &&
3901  (GetPointer<const gimple_node>(second_tree_node)->vdef))
3902  {
3904  "<--No because operations with side effect cannot be executed in the same clock cycle of the "
3905  "condition which controls it");
3906  return false;
3907  }
3908  if(first_store && !(!is_operation_bounded(second_statement_index)) &&
3909  is_operation_PI_registered(second_statement_index, GetFuType(second_statement_index)))
3910  {
3911  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--");
3912  return false;
3913  }
3915  if(parameters->IsParameter("bus-no-chain") && parameters->GetParameter<int>("bus-no-chain") == 1 &&
3916  ((CanImplementSetNotEmpty(first_statement_index) &&
3917  is_indirect_access_memory_unit(GetFuType(first_statement_index))) ||
3918  (CanImplementSetNotEmpty(second_statement_index) &&
3919  is_indirect_access_memory_unit(GetFuType(second_statement_index)))))
3920  {
3922  "<--No because one of the operations is an access through bus");
3923  return false;
3924  }
3925  if(parameters->IsParameter("load-store-no-chain") && parameters->GetParameter<int>("load-store-no-chain") == 1 &&
3926  (behavioral_helper->IsLoad(first_statement_index) || second_load || first_store || second_store))
3927  {
3929  "<--No because one of the operations is a load or a store");
3930  return false;
3931  }
3932  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Yes");
3933  return true;
3934 }
3935 
3937 {
3939  op_graph = hls_manager->CGetFunctionBehavior(function_index)->CGetOpGraph(FunctionBehavior::CFG);
3940  HLS_C = hls->HLS_C;
3941  HLS_D = hls->HLS_D;
3942  behavioral_helper = hls_manager->CGetFunctionBehavior(function_index)->CGetBehavioralHelper();
3943  Rmem = hls_manager->Rmem;
3944  TreeM = hls_manager->get_tree_manager();
3945  connection_time_ratio =
3946  HLS_D->has_parameter("connection_time_ratio") ? HLS_D->get_parameter<double>("connection_time_ratio") : 1;
3947  controller_delay_multiplier = HLS_D->has_parameter("controller_delay_multiplier") ?
3948  HLS_D->get_parameter<double>("controller_delay_multiplier") :
3949  1;
3950  setup_multiplier = HLS_D->has_parameter("setup_multiplier") ? HLS_D->get_parameter<double>("setup_multiplier") : 1.0;
3951  time_multiplier = HLS_D->has_parameter("time_multiplier") ? HLS_D->get_parameter<double>("time_multiplier") : 1.0;
3952  mux_time_multiplier =
3953  HLS_D->has_parameter("mux_time_multiplier") ? HLS_D->get_parameter<double>("mux_time_multiplier") : 1.0;
3954  memory_correction_coefficient = HLS_D->has_parameter("memory_correction_coefficient") ?
3955  HLS_D->get_parameter<double>("memory_correction_coefficient") :
3956  0.7;
3957 
3958  connection_offset = parameters->IsParameter("ConnectionOffset") ?
3959  parameters->GetParameter<double>("ConnectionOffset") :
3960  parameters->IsParameter("RelativeConnectionOffset") ?
3961  parameters->GetParameter<double>("RelativeConnectionOffset") * get_setup_hold_time() :
3962  HLS_D->has_parameter("RelativeConnectionOffset") ?
3963  HLS_D->get_parameter<double>("RelativeConnectionOffset") * get_setup_hold_time() :
3964  HLS_D->has_parameter("ConnectionOffset") ? HLS_D->get_parameter<double>("ConnectionOffset") :
3966 
3967  output_DSP_connection_time =
3968  parameters->IsParameter("OutputDSPConnectionRatio") ?
3969  parameters->GetParameter<double>("OutputDSPConnectionRatio") * get_setup_hold_time() :
3970  HLS_D->has_parameter("OutputDSPConnectionRatio") ?
3971  HLS_D->get_parameter<double>("OutputDSPConnectionRatio") * get_setup_hold_time() :
3973  output_carry_connection_time =
3974  parameters->IsParameter("OutputCarryConnectionRatio") ?
3975  parameters->GetParameter<double>("OutputCarryConnectionRatio") * get_setup_hold_time() :
3976  HLS_D->has_parameter("OutputCarryConnectionRatio") ?
3977  HLS_D->get_parameter<double>("OutputCarryConnectionRatio") * get_setup_hold_time() :
3979  fanout_coefficient = parameters->IsParameter("FanOutCoefficient") ?
3980  parameters->GetParameter<double>("FanOutCoefficient") :
3982  max_fanout_size = parameters->IsParameter("MaxFanOutSize") ? parameters->GetParameter<size_t>("MaxFanOutSize") :
3984  DSPs_margin =
3985  HLS_D->has_parameter("DSPs_margin") && parameters->getOption<double>(OPT_DSP_margin_combinational) == 1.0 ?
3986  HLS_D->get_parameter<double>("DSPs_margin") :
3987  parameters->getOption<double>(OPT_DSP_margin_combinational);
3988  DSPs_margin_stage =
3989  HLS_D->has_parameter("DSPs_margin_stage") && parameters->getOption<double>(OPT_DSP_margin_pipelined) == 1.0 ?
3990  HLS_D->get_parameter<double>("DSPs_margin_stage") :
3991  parameters->getOption<double>(OPT_DSP_margin_pipelined);
3992  DSP_allocation_coefficient = HLS_D->has_parameter("DSP_allocation_coefficient") &&
3993  parameters->getOption<double>(OPT_DSP_allocation_coefficient) == 1.0 ?
3994  HLS_D->get_parameter<double>("DSP_allocation_coefficient") :
3995  parameters->getOption<double>(OPT_DSP_allocation_coefficient);
3996  minimumSlack = std::numeric_limits<double>::max();
3997  n_complex_operations = 0;
3998  mux_timing_db = InitializeMuxDB(AllocationInformationConstRef(this, null_deleter())).first;
3999  mux_area_db = InitializeMuxDB(AllocationInformationConstRef(this, null_deleter())).second;
4000  DSP_x_db = std::get<0>(InitializeDSPDB(AllocationInformationConstRef(this, null_deleter())));
4001  DSP_y_db = std::get<1>(InitializeDSPDB(AllocationInformationConstRef(this, null_deleter())));
4002 }
4003 
4005 {
4006  HLSIR::Clear();
4007  op_graph = OpGraphConstRef();
4008  HLS_C = HLS_constraintsConstRef();
4009  HLS_D = HLS_deviceConstRef();
4010  behavioral_helper = BehavioralHelperConstRef();
4011  Rmem = memoryConstRef();
4012  TreeM = tree_managerConstRef();
4013 
4014  minimumSlack = std::numeric_limits<double>::max();
4015  n_complex_operations = 0;
4016  id_to_fu_names.clear();
4017  is_vertex_bounded_rel.clear();
4018  list_of_FU.clear();
4019  memory_units.clear();
4020  nports_map.clear();
4021  precision_map.clear();
4022  proxy_function_units.clear();
4023  proxy_memory_units.clear();
4024  proxy_wrapped_units.clear();
4025  tech_constraints.clear();
4026  node_id_to_fus.clear();
4027  fus_to_node_id.clear();
4028  binding.clear();
4029  memory_units_sizes.clear();
4030  vars_to_memory_units.clear();
4031  precomputed_pipeline_unit.clear();
4032  single_bool_test_cond_expr_units.clear();
4033  simple_pointer_plus_expr.clear();
4034  vars_to_memory_units.clear();
4035  precomputed_pipeline_unit.clear();
4036  single_bool_test_cond_expr_units.clear();
4037  simple_pointer_plus_expr.clear();
4038  ssa_roots.clear();
4039  ssa_bb_versions.clear();
4040  ssa_cond_exprs.clear();
4041  cond_expr_bb_versions.clear();
4042 }
4043 double AllocationInformation::GetToDspRegisterDelay(const unsigned int statement_index) const
4044 {
4045  if(statement_index == ENTRY_ID || statement_index == EXIT_ID)
4046  {
4047  return 0.0;
4048  }
4049  if(CanImplementSetNotEmpty(statement_index) && get_DSPs(GetFuType(statement_index)) != 0.0)
4050  {
4051  return 0.0;
4052  }
4053  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Checking path to DSP register");
4054  double ret = 0.0;
4055  const auto zero_distance_operations = GetZeroDistanceOperations(statement_index);
4056  const auto statement_bb_index = GetPointer<const gimple_node>(TreeM->CGetTreeNode(statement_index))->bb_index;
4057 #if 0
4058  const auto fd = GetPointer<const function_decl>(TreeM->CGetTreeNode(function_id));
4059  const auto sl = GetPointer<const statement_list>(GET_CONST_NODE(fd->body));
4060  const auto blocks = sl->list_of_bloc;
4061  const auto statement_bb = blocks.find(statement_bb_index)->second;
4062 #endif
4063  const auto tn = TreeM->CGetTreeNode(statement_index);
4064  const bool is_carry = [&]() -> bool {
4065  const auto ga = GetPointer<const gimple_assign>(tn);
4066  if(!ga)
4067  {
4068  return false;
4069  }
4070  const auto op1_kind = GET_CONST_NODE(ga->op1)->get_kind();
4071  if(op1_kind == plus_expr_K || op1_kind == minus_expr_K || op1_kind == ternary_plus_expr_K ||
4072  op1_kind == ternary_pm_expr_K || op1_kind == ternary_mp_expr_K || op1_kind == ternary_mm_expr_K ||
4073  op1_kind == eq_expr_K || op1_kind == ne_expr_K || op1_kind == gt_expr_K || op1_kind == ge_expr_K ||
4074  op1_kind == lt_expr_K || op1_kind == le_expr_K || op1_kind == pointer_plus_expr_K)
4075  {
4076  return true;
4077  }
4078  else
4079  {
4080  return false;
4081  }
4082  }();
4083  for(const auto zero_distance_operation : zero_distance_operations)
4084  {
4085  if(CanImplementSetNotEmpty(zero_distance_operation) && get_DSPs(GetFuType(zero_distance_operation)) != 0.0)
4086  {
4087  const auto zero_distance_operation_bb_index =
4088  GetPointer<const gimple_node>(TreeM->CGetTreeNode(zero_distance_operation))->bb_index;
4089  auto to_dsp_register_delay =
4090  (parameters->IsParameter("ToDSPRegisterDelay") ? parameters->GetParameter<double>("ToDSPRegisterDelay") :
4091  0.6) *
4092  get_setup_hold_time();
4094  if(statement_bb_index != zero_distance_operation_bb_index)
4095  {
4097  "---" + STR(zero_distance_operation) + " mapped on DSP on different BB");
4098  to_dsp_register_delay += 2 * ((parameters->IsParameter("ToDSPRegisterDelay") ?
4099  parameters->GetParameter<double>("ToDSPRegisterDelay") :
4100  0.6) *
4101  get_setup_hold_time());
4102  }
4103  else
4104  {
4106  "---" + STR(zero_distance_operation) + " mapped on DSP on same BB");
4107  }
4108  if(is_carry)
4109  {
4110  to_dsp_register_delay += output_carry_connection_time;
4111  }
4112  if(to_dsp_register_delay > ret)
4113  {
4114  ret = to_dsp_register_delay;
4115  }
4116  }
4117  else
4118  {
4120  "---" + STR(zero_distance_operation) + " not mapped on DSP");
4121  }
4122  }
4123  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Checked path to DSP register: " + STR(ret));
4124  return ret;
4125 }
4126 
4128 {
4129  const auto bb_version = hls_manager->CGetFunctionBehavior(function_index)->GetBBVersion();
4130  if(zero_distance_ops_bb_version.find(statement_index) != zero_distance_ops_bb_version.end() &&
4131  zero_distance_ops_bb_version.find(statement_index)->second == bb_version)
4132  {
4134  "---Get Zero Distance Operations of " + STR(statement_index) + " - Using cached values");
4135  return zero_distance_ops.find(statement_index)->second;
4136  }
4137  else
4138  {
4140  "-->Computing Zero Distance Operations of " + STR(statement_index));
4141  zero_distance_ops[statement_index].clear();
4142  zero_distance_ops_bb_version[statement_index] = bb_version;
4143  CustomSet<unsigned int> to_be_analyzed_ops;
4144  CustomSet<unsigned int> already_analyzed;
4145  to_be_analyzed_ops.insert(statement_index);
4146  while(to_be_analyzed_ops.size())
4147  {
4148  const auto current_tn_index = *(to_be_analyzed_ops.begin());
4149  to_be_analyzed_ops.erase(to_be_analyzed_ops.begin());
4150  already_analyzed.insert(current_tn_index);
4152  "-->Considering " + STR(TreeM->CGetTreeNode(current_tn_index)));
4153  const auto current_ga = GetPointer<const gimple_assign>(TreeM->CGetTreeNode(current_tn_index));
4154  if(!current_ga)
4155  {
4156  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Not continuing since not gimple_assign ");
4157  continue;
4158  }
4159  const auto current_sn = GetPointer<const ssa_name>(GET_CONST_NODE(current_ga->op0));
4160  if(!current_sn)
4161  {
4162  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Not continuing since not ssa");
4163  continue;
4164  }
4165  if(current_tn_index != statement_index)
4166  {
4167  if(GetCycleLatency(statement_index) > 1)
4168  {
4169  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Not continuing since multi-cycle");
4170  continue;
4171  }
4172  if(GetTimeLatency(
4173  current_tn_index,
4174  CanImplementSetNotEmpty(current_tn_index) ? GetFuType(current_tn_index) : fu_binding::UNKNOWN, 0)
4175  .first > 0.001)
4176  {
4177  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Not continuing since not zero delay");
4178  continue;
4179  }
4180  }
4181  for(const auto& use_stmt : current_sn->CGetUseStmts())
4182  {
4183  const auto use_stmt_index = use_stmt.first->index;
4184  if(already_analyzed.find(use_stmt_index) != already_analyzed.end())
4185  {
4186  continue;
4187  }
4188 #if 0
4189  if(GetConnectionTime(current_tn_index, use_stmt_index, AbsControlStep(0, AbsControlStep::UNKNOWN)) > 0.0)
4190  {
4191  continue;
4192  }
4193 #endif
4194  to_be_analyzed_ops.insert(use_stmt_index);
4195  zero_distance_ops[statement_index].insert(use_stmt_index);
4196  }
4198  "<--Considered " + STR(TreeM->CGetTreeNode(current_tn_index)));
4199  }
4201  "<--Computed Zero Distance Operations of " + STR(statement_index));
4202  return zero_distance_ops[statement_index];
4203  }
4204 }
4205 
4206 void node_kind_prec_info::print(std::ostream& os) const
4207 {
4208  os << "node_kind: " << node_kind << "\n";
4209  os << "node_kind: " << node_kind << "\n";
4210  for(auto el : input_prec)
4211  {
4212  os << el << " ";
4213  }
4214  os << "\n";
4215  for(auto el : base128_input_nelem)
4216  {
4217  os << el << " ";
4218  }
4219  os << "\n";
4220  for(auto el : real_input_nelem)
4221  {
4222  os << el << " ";
4223  }
4224  os << "\n";
4225  os << "output_prec: " << output_prec << "\n";
4226  os << "base128_output_nelem: " << base128_output_nelem << "\n";
4227  os << "real_output_nelem: " << real_output_nelem << "\n";
4228  os << "is_single_bool_test_cond_expr: " << (is_single_bool_test_cond_expr ? "T" : "F") << "\n";
4229  os << "is_simple_pointer_plus_expr: " << (is_single_bool_test_cond_expr ? "T" : "F") << "\n";
4230 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
double get_worst_execution_time(const unsigned int fu_name) const
Returns the worst execution time for all the operations associated with the functional unit...
#define READ_COND_STD
void print_allocated_resources() const
Prints the actual allocation.
double GetCondExprTimeLatency(const unsigned int operation_index) const
Return the execution time of a cond expr corresponding to the gimple_phi.
static bool is_a_struct(const tree_managerConstRef &TM, const unsigned int index)
Return if treenode index is a record.
double get_area(const unsigned int fu_name) const
Returns the area for a given functional unit.
#define MEMORY_CTRL_TYPE_DPROXY
std::vector< unsigned int > DSP_x_db
store DSP x sizes
HLS_constraintsConstRef HLS_C
HLS constraints.
static tree_nodeConstRef GetFormalIth(const tree_nodeConstRef &obj, unsigned int parm_index)
Return the type of the ith formal parameter in case index_obj is a call_expr.
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
static bool IsUnionType(const tree_nodeConstRef &type)
Return if treenode is an union.
static bool IsComplexType(const tree_nodeConstRef &type)
Return if treenode is a complex.
bool is_vertex_bounded(const unsigned int fu_name) const
Checks if the functional unit is uniquely bounded to a vertex.
Data structure representing the entire HLS information.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
Collect information about resource area.
unsigned int GetCycleLatency(const unsigned int operationID) const
Return the latency of an operation in cycle.
void Initialize() override=0
Initialize all the data structure.
Definition: hls_ir.cpp:50
double get_correction_time(unsigned int fu, const std::string &operation_name, unsigned int n_ins) const
return a time to be subtracted to the execution time/stage period
static std::vector< unsigned long long > GetArrayDimensions(const tree_nodeConstRef &node)
Return the dimension of the array.
#define NUM_CST_allocation_default_output_DSP_connection_ratio
The default value for the connection ratio between the output delay of a DSP and the setup delay...
static unsigned long long AccessedMaximumBitsize(const tree_nodeConstRef &type_node, unsigned long long bitsize)
return the maximum bitsize associated with the elements accessible through type_node ...
Basic block control flow graph.
File containing functions and utilities to support the printing of debug messagges.
unsigned long long get_prec(const unsigned int fu_name) const
return the precision of the given functional unit
#define PRINT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
int flag
Definition: SPARC-GCC.h:58
static bool is_int(const tree_managerConstRef &TM, const unsigned int index)
Return true if the treenode is of integer type.
std::string ToString() const
Print this node as string in gimple format.
#define DEBUG_LEVEL_PEDANTIC
very verbose debugging print is performed.
technology_nodeRef get_fu(const std::string &fu_name, const std::string &Library) const
Return the reference to a component given its name.
This file contains the structures needed to manage a graph that will represent the state transition g...
static bool IsConstant(const tree_nodeConstRef &node)
Return if a tree node is a constant object.
bool is_direct_access_memory_unit(unsigned int fu_type) const
return true in case fu type is a memory unit with direct access channels
double get_execution_time_dsp_modified(const unsigned int fu_name, const technology_nodeRef &node_op) const
CustomMap< unsigned long long, CustomUnorderedMapStable< unsigned int, double > > mux_timing_db
store mux timing for the current technology
ControlStep op_et_to_cycles(double et, double clock_period) const
Calculates the control steps required for a specific operation.
string target
Definition: lenet_tvm.py:16
const tree_nodeRef CGetTreeReindex(const unsigned int i) const
Return a tree_reindex wrapping the i-th tree_node.
double GetPhiConnectionLatency(const unsigned int statement_index) const
Return the connection delay due to phi.
#define GET_CLASS(obj)
Macro returning the actual type of an object.
#define LUT_EXPR_STD
Dest from_strongtype_cast(Source source)
CustomMap< unsigned long long, CustomUnorderedMapStable< unsigned int, double > > mux_area_db
store mux timing for the current technology
const structural_objectRef get_circ() const
Get a reference to circ field.
const std::vector< std::string > SplitString(const std::string &input, const std::string &separators)
Function which splits a string into tokens.
static bool IsArrayEquivType(const tree_nodeConstRef &type)
Return true if treenode is an array or it is equivalent to an array (record recursively having a sing...
#define ARRAY_1D_STD_BRAM_NN_SDS_BUS
#define GIMPLE_PRAGMA_STD
T resize_1_8_pow2(T value)
CustomUnorderedMap< unsigned int, std::pair< std::string, std::string > > id_to_fu_names
map between the functional unit identifier and the pair (library, fu) of names for the unit ...
double GetToDspRegisterDelay(const unsigned int statement_index) const
Add the delay to reach a DSP register if necessary.
#define SF_FFDATA_CONVERTER_64_32_STD
bool is_vertex_bounded_with(const unsigned int v, unsigned int &fu_name) const
In case the vertex is bounded to a particular functional unit, it returns true and the functional uni...
refcount< const tree_manager > tree_managerConstRef
mathematical utility function not provided by standard libraries
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
static std::string GetString(const enum kind k)
Given a kind, return the corresponding string.
Definition: tree_node.cpp:120
static tree_nodeConstRef CGetElements(const tree_nodeConstRef &type)
Given an array or a vector return the element type.
#define GET_NAME(data, vertex_index)
Helper macro returning the name associated with a node.
std::pair< std::string, std::string > get_fu_name(unsigned int id) const
Returns the name of the functional unit, associated with the name of the library, given the correspon...
#define MEMORY_CTRL_TYPE_D00
#define ARRAY_1D_STD_BRAM_NN_SDS
bool CanImplementSetNotEmpty(const unsigned int v) const
Return if any functional unit has been allocated for an operation.
CustomOrderedMap< T, U > CustomMap
Definition: custom_map.hpp:167
const HLS_deviceRef HLS_D
reference to the information representing the target for the synthesis
Definition: hls.hpp:107
exceptions managed by PandA
bool has_constant_in(unsigned int fu_name) const
return true in case the functional unit has an input connected to a constant value ...
double get_stage_period_dsp_modified(const unsigned int fu_name, const technology_nodeRef &node_op) const
double estimate_muxNto1_area(unsigned long long fu_prec, unsigned int mux_ins) const
Return the area due to mux with n-inputs.
double get_DSPs(const unsigned int fu_name) const
return an estimation of the number of DSPs used by the unit
bool is_proxy_unit(const unsigned int fu_name) const
check if a functional unit is a proxy
double mux_time_unit_raw(unsigned long long fu_prec) const
#define NUM_CST_allocation_default_connection_offset
The default value for connection offset.
static const ControlStep UNKNOWN
Constant used to specify unknown control step.
Definition: schedule.hpp:93
Collect information about resource performance.
void print(std::ostream &os) const
#define ARRAY_1D_STD_BRAM_SDS
HLS_deviceConstRef HLS_D
reference to the information representing the target for the synthesis
time_infoRef time_m
class representing the timing information associated with this operation
const std::map< unsigned int, unsigned int > & get_proxy_memory_units() const
return the set of proxy memory units
refcount< const OpGraph > OpGraphConstRef
Definition: op_graph.hpp:923
#define MEMORY_TYPE_SYNCHRONOUS_SDS_BUS
ControlStep get_initiation_time() const
Definition: time_info.cpp:90
#define LIBRARY_STD_FU
standard library where all standard HLS resources are defined
#define min(x, y)
double get_stage_period(const unsigned int fu_name, const vertex v, const OpGraphConstRef g) const
Return the stage period for a given vertex and a given pipelined functional unit. ...
unsigned int get_n_complex_operations() const
double compute_normalized_area(unsigned int fu_s1) const
compute a number representing the "weight" of the functional unit
CustomUnorderedMap< unsigned int, CustomOrderedSet< unsigned int > > fus_to_node_id
reverse map putting into relation functional units with the operations that can be mapped on ...
double GetClockPeriodMargin() const
Return the margin to be considered when performing scheduling.
Class specification of the manager of the technology library data structures.
bool is_proxy_function_unit(const unsigned int fu_name) const
check if a functional unit is a proxy function unit
static std::string extract_bambu_provided_name(unsigned long long prec_in, unsigned long long prec_out, const HLS_managerConstRef hls_manager, technology_nodeRef &current_fu)
Allocation_MinMax
Definition: allocation.hpp:89
This class specifies the characteristic of a particular functional unit.
double get_worst_stage_period(const unsigned int fu_name) const
Returns the worst stage period for all the operations associated with the functional unit...
static technology_nodeRef get_fu(const std::string &fu_name, const HLS_managerConstRef hls_manager)
Returns the technology_node associated with the given operation.
Data structure describing a basic block at tree level.
double time_multiplier
coefficient used to modify execution time and stage time
Base class description of data information associated with each node of a graph.
static unsigned int get_type_index(const tree_managerConstRef &TM, const unsigned int index, long long int &vec_size, bool &is_a_pointer, bool &is_a_function)
Return the treenode index of the type of index.
std::pair< double, double > GetTimeLatency(const unsigned int operation, const unsigned int functional_unit, const unsigned int stage=0) const
Return the execution time of (a stage of) an operation.
#define ASSIGN_SIGNED_STD
refcount< const AllocationInformation > AllocationInformationConstRef
tree_managerConstRef TreeM
The tree manager.
redefinition of map to manage ordered/unordered structures
std::tuple< unsigned int, unsigned int > io_binding_type
tuple set used to represent the required values or the constant default value associated with the inp...
Absolute Control step First field is the basic block Second field is the relative control step...
Definition: schedule.hpp:89
#define MEMORY_TYPE_ASYNCHRONOUS
#define GIMPLE_LABEL_STD
#define MEMORY_CTRL_TYPE_PROXY
const tree_nodeConstRef CGetTreeNode(const unsigned int i) const
unsigned int get_worst_number_of_cycles(const unsigned int fu_name) const
refcount< technology_node > technology_nodeRef
refcount definition of the class
virtual enum kind get_kind() const =0
Virtual function returning the type of the actual class.
#define GIMPLE_PHI_STD
double GetStatementArea(const unsigned int statement_index) const
Returns the area for a given statement.
#define THROW_WARNING(str_expr)
helper function used to throw a warning in a standard way: though it uses PRINT_DBG_MEX, the debug level used is such that the message is always printed
Definition: exceptions.hpp:300
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
#define MEMORY_CTRL_TYPE_SPROXY
CustomUnorderedMap< std::pair< unsigned int, std::string >, CustomOrderedSet< unsigned int > > node_id_to_fus
for each operation (node-id, operation) return the set of functional unit that can be used ...
#define max
Definition: backprop.h:17
unsigned int max_number_of_operations(unsigned int fu) const
return the maximum number of operations that insists on the same type of functional unit ...
std::vector< unsigned int > DSP_y_db
store DSP y sizes
double estimate_mux_time(unsigned int fu_name) const
estimate the delay of a mux that can be uses to mux the input of the given functional unit ...
const std::map< unsigned int, std::string > & get_proxy_wrapped_units() const
return the set of proxy wrapped units
#define GIMPLE_ASM_STD
unsigned int get_cycles(const unsigned int fu_name, const unsigned int v) const
Return the number of cycles for given vertex and a given functional unit.
std::map< unsigned int, std::string > proxy_wrapped_units
put into relation proxy wrapped units with shared functions
structural_managerRef top
Store the top description.
Definition: hls.hpp:164
static bool IsUnsignedIntegerType(const tree_nodeConstRef &type)
Return true if the treenode is of unsigned integer type.
#define MEMORY_TYPE_SYNCHRONOUS_UNALIGNED
void update(const unsigned int name, int delta)
Function used to update the copy of the technology constraints.
const tree_nodeRef get_tree_node_const(unsigned int i) const
Return the reference to the i-th tree_node Constant version of get_tree_node.
static bool IsSignedIntegerType(const tree_nodeConstRef &type)
Return true if the treenode is of integer type.
unsigned int operator()(const unsigned int name) const
Required functor function used to compute the number of resources associated with the given resource...
const OpNodeInfoConstRef CGetOpNodeInfo(const vertex node) const
Returns the info associated with a node.
Definition: op_graph.hpp:843
std::vector< unsigned int > tech
copy of the technology constraints
static bool IsArrayType(const tree_nodeConstRef &type)
Return true if treenode is an array.
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
bool starts_with(const std::string &str, const std::string &pattern)
int delay(int ritardo)
Definition: delay.c:1
static const std::pair< const CustomMap< unsigned long long, CustomUnorderedMapStable< unsigned int, double > > &, const CustomMap< unsigned long long, CustomUnorderedMapStable< unsigned int, double > > & > InitializeMuxDB(const AllocationInformationConstRef allocation_information)
Compute the values for the initialization of the multiplexer characteristics database.
ScheduleRef Rsch
Store the refcounted scheduling of the operations.
Definition: hls.hpp:118
double get_attribute_of_fu_per_op(const vertex v, const OpGraphConstRef g, const Allocation_MinMax allocation_min_max, op_target target, unsigned int &fu_name, bool &flag, const updatecopy_HLS_constraints_functor *CF=nullptr) const
This method returns the min or the max value of the execution time/power consumption/initiation time ...
CustomSet< unsigned int > ComputeDrivenCondExpr(const unsigned int ssa) const
Compute the cond_expr indirectly driven by a ssa.
double get_resource_value(value_t val) const
Definition: area_info.cpp:77
CustomUnorderedMap< unsigned int, std::pair< std::string, unsigned int > > binding
Puts into relation operation with type and functional units.
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
#define EXIT_ID
constant used to represent tree node index of exit operation
Definition: op_graph.hpp:81
unsigned int get_proxy_memory_var(const unsigned int fu_name) const
return the var associated with the proxy unit
double estimate_muxNto1_delay(unsigned long long fu_prec, unsigned int mux_ins) const
Return the delay due to mux with n-inputs.
const unsigned int function_index
The index of the function to which this IR is associated.
bool IsVariableExecutionTime(const unsigned int operation_index) const
Return true if the variable execution time depends on the scheduling.
double mux_area_unit_raw(unsigned long long fu_prec) const
std::string get_latency_string(const std::string &lat) const
void Clear() override
Clear all the data structure.
static bool IsBooleanType(const tree_nodeConstRef &type)
Return true if the treenode is of bool type.
void Initialize() override
Initialize all the data structure.
This class specifies the characteristic of a particular operation working on a given functional unit...
area_infoRef area_m
This variable stores the resource information of the component.
bool is_operation_PI_registered(const OpGraphConstRef g, const vertex &op, unsigned int fu_type) const
Checks if the given operation has its primary input registered or not.
Data structure used to store the schedule of the operations.
bool CanBeMerged(const unsigned int first_operation, const unsigned int second_operation) const
Return true if the two operations can be mapped on the same LUT.
#define ASSIGN_REAL_STD
bool is_read_cond(const unsigned int fu_name) const
Checks if the functional unit implements a READ_COND operation.
Control flow graph.
#define NUM_CST_allocation_default_states_number_normalization
The default value used in computation of controller delay.
#define NUM_CST_allocation_default_states_number_normalization_linear_factor
The default value used in computation of controller delay when basic block are considered.
std::vector< technology_nodeRef > list_of_FU
Stores the list of the functional units.
void set_number_channels(unsigned int fu_name, unsigned int n_ports)
set the number of ports associated with the functional unit
bool is_direct_proxy_memory_unit(unsigned int fu_type) const
return true in case4 fu type is a memory unit accessed through a proxy module
Class specification of the data structures used to manage technology information. ...
~AllocationInformation() override
Destructor.
#define ARRAY_1D_STD_DISTRAM_SDS
OpGraphConstRef op_graph
The operation graph.
bool can_implement(const unsigned int fu_id, const vertex v) const
Checks if the operation associated with a vertex can be implemented by a given functional unit...
double get_area_value() const
Return the nominal value for the area of the component.
Definition: area_info.cpp:57
AllocationInformation(const HLS_managerRef _hls_manager, const unsigned int _function_index, const ParameterConstRef parameters)
Constructor.
const unsigned int index
Represent the index read from the raw file and the index-1 of the vector of tree_node associated to t...
Definition: tree_node.hpp:146
#define index(x, y)
Definition: Keccak.c:74
CustomOrderedSet< unsigned int > is_vertex_bounded_rel
Store the set of functional units (identifiers) uniquely bounded.
redefinition of set to manage ordered/unordered structures
#define GIMPLE_NOP_STD
#define ARRAY_1D_STD_BRAM_NN
double mux_time_unit(unsigned long long fu_prec) const
const operation_vec & get_operations() const
Return the operations that the functional unit can handle.
#define MEMORY_TYPE_SYNCHRONOUS_SDS
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
double get_execution_time() const
Definition: time_info.cpp:80
double estimate_controller_delay_fb() const
estimate the delay of the controller in feedback mode
static bool IsVectorType(const tree_nodeConstRef &type)
Return true if the treenode is a vector.
const std::map< unsigned int, std::string > & get_proxy_function_units() const
return the set of proxy function units
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
#define MUX_N_TO_1
#define ENTRY_STD
double DSPs_margin_stage
coefficient used to modify DSPs stage period
Classes specification of the tree_node data structures.
static std::string NormalizeTypename(const std::string &id)
Return normalized name of types and variables.
This package is used by all HLS packages to manage resource constraints and characteristics.
void GetNodeTypePrec(const vertex node, const OpGraphConstRef g, node_kind_prec_infoRef info, HLS_manager::io_binding_type &constant_id, bool is_constrained) const
Extract the node kind and precision, if available.
bool is_proxy_memory_unit(const unsigned int fu_name) const
Returns true if the fu_name is a proxy memory unit.
static const double epsilon
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
double time_m_execution_time(operation *op) const
return the execution time of the operation corrected by time_multiplier factor
#define GIMPLE_RETURN_STD
artificial functional units
#define NOP_STD
static const unsigned int UNKNOWN
The value used to identified unknown functional unit.
Definition: fu_binding.hpp:178
Data structure definition for HLS constraints.
#define NUM_CST_allocation_default_states_number_normalization_BB
The default value used in computation of controller delay when basic block are considered.
double estimate_mux_area(unsigned int fu_name) const
Estimate the area of a mux attached to a given functional unit.
#define ARRAY_1D_STD_DISTRAM_NN_SDS
bool is_operation_bounded(const OpGraphConstRef g, const vertex &op, unsigned int fu_type) const
Checks if the given operation has a bounded execution time or not.
This file collects some utility functions.
bool can_be_asynchronous_ram(tree_managerConstRef TM, unsigned int var, unsigned int threshold, bool is_read_only_variable, unsigned int channel_number)
#define MEMORY_CTRL_TYPE_PROXYN
bool is_one_cycle_direct_access_memory_unit(unsigned int fu_type) const
return true in case the functional unit is a direct_access memory unit with a single clock latency fo...
null deleter
Definition: refcount.hpp:51
double setup_multiplier
coefficient used to modify setup value
constants used by HLS constants
std::vector< unsigned int > tech_constraints
For each functional unit (position in the vector), tech_constraints stores the maximum number of reso...
bool is_simple_pointer_plus_expr(const unsigned int fu_name) const
return true in case the functional unit implement a pointer_plus operation and the operands are const...
const unsigned int & address_bitsize
std::map< unsigned int, unsigned int > proxy_memory_units
put into relation proxy memory units with variables
std::string id_type
Original type id of the structural object.
const structural_type_descriptorRef & get_typeRef() const
Return the type descriptor of the structural_object.
bool is_dual_port_memory(unsigned int fu_type) const
return true in case the memory has decoupled addresses for writing and reading
const CustomOrderedSet< unsigned int > & can_implement_set(const vertex v) const
Returns the set of functional units that can be used to implement the operation associated with verte...
#define COND_EXPR_STD
#define ASSIGN_UNSIGNED_STD
struct definition of the type node structures.
Definition: tree_node.hpp:1318
int el
Definition: adpcm.c:105
technology_nodeRef get_operation(const std::string &op_name) const
This method returns the operationRef from its name if the functional unit contains an operation of ty...
Class specification of the tree_reindex support class.
#define ENTRY_ID
constant used to represent tree node index of entry operation
Definition: op_graph.hpp:79
static bool is_an_union(const tree_managerConstRef &TM, const unsigned int index)
Return if treenode index is an union.
static bool is_concat_bit_ior_expr(const tree_managerConstRef &TM, const unsigned int index)
check if a given tree node is a concatenation operation
unsigned int get_number_channels(unsigned int fu_name) const
return the number of channels available for the functional unit
std::string get_string_name(unsigned int fu_name) const
Returns the name of the functional for debug purpose.
std::map< unsigned int, std::string > proxy_function_units
put into relation proxy function units with shared functions
bool CanBeChained(const unsigned int first_statement_index, const unsigned int second_statement_index) const
Check if two statements can be chained.
Data structure used to store the functional-unit binding of the vertexes.
static void get_array_dimensions(const tree_managerConstRef &TM, const unsigned int index, std::vector< unsigned long long > &dims)
Return the dimension of the array.
#define WORK_LIBRARY
working library.
#define MEMORY_CTRL_TYPE_DPROXYN
#define INFINITE_UINT
UNSIGNED INT representing infinite.
Definition: utility.hpp:70
#define ARRAY_1D_STD_BRAM_SDS_BUS
Class specification of the basic_block structure.
technology_managerRef get_technology_manager() const
Returns the technology manager.
bool is_assign(const unsigned int fu_name) const
Checks if the functional unit implements an ASSIGN operation.
unsigned int get_memory_var(const unsigned int fu_name) const
Returns the base address of the functional unit.
static const std::tuple< const std::vector< unsigned int > &, const std::vector< unsigned int > & > InitializeDSPDB(const AllocationInformationConstRef allocation_information)
Compute the values for the initialization of the DSP characteristics database.
#define NUM_CST_allocation_default_output_carry_connection_ratio
The default value for the connection ratio between the output delay of a carry and the setup delay...
static tree_nodeConstRef CGetType(const tree_nodeConstRef &node)
Return the treenode of the type of node.
CustomSet< unsigned int > ComputeRoots(const unsigned int ssa, const AbsControlStep cs) const
Compute the roots to be considered for fan out computation.
static bool IsStructType(const tree_nodeConstRef &type)
Return true if treenode is a record.
#define NUM_CST_allocation_default_fanout_coefficent
The default value used in computation of fanout delay.
#define ADDER_STD
constraint functor used by get_attribute_of_fu_per_op
#define MEMORY_CTRL_TYPE_SPROXYN
unsigned int get_number_fu(unsigned int fu_name) const
Returns the number of functional unit given its id.
#define EXIT_STD
bool is_return(const unsigned int fu_name) const
Checks if the functional unit implements a RETURN operation.
Classes specification of the tree_node data structures not present in the gcc.
unsigned int min_number_of_resources(const vertex v) const
Computes the minum number of resources implementing the operation associated with the vertex v...
#define GIMPLE_GOTO_STD
this class is used to manage the command-line or XML options.
double GetConnectionTime(const unsigned int first_operation, const unsigned int second_operation, const AbsControlStep cs) const
Return the connection time for a couple of operations or the phi overhead for a single operation...
double time_m_stage_period(operation *op) const
return the stage time of the operation corrected by time_multiplier factor
void Clear() override=0
Clear all the data structure.
Definition: hls_ir.cpp:55
#define MUX_GATE_STD
updatecopy_HLS_constraints_functor(const AllocationInformationRef allocation_information)
Constructor.
double DSPs_margin
coefficient used to modify DSPs execution time
Class implementation of the structural_manager.
bool is_memory_unit(const unsigned int fu_name) const
Returns true if the fu_name is a memory unit.
bool is_indirect_access_memory_unit(unsigned int fu) const
return true in case fu type is a resource unit performing an indirect access to memory ...
StateTransitionGraphManagerRef STG
Store the refcounted state transition graph.
Definition: hls.hpp:124
Data structure that contains all information about high level synthesis process.
Definition: hls.hpp:83
const HLS_managerRef hls_manager
The HLS manager.
Definition: hls_ir.hpp:55
const HLS_constraintsRef HLS_C
store the HLS constraints
Definition: hls.hpp:110
bool is_proxy_wrapped_unit(const unsigned int fu_name) const
check if a functional unit is a proxy wrapped unit
This package is used by all HLS packages to manage resource constraints and characteristics.
double get_stage_period() const
Definition: time_info.cpp:100
operation()
Constructor.
bool has_to_be_synthetized(const unsigned int fu_name) const
Checks if the functional unit has to be synthetized.
std::vector< technology_nodeRef > operation_vec
Type definition of a vector of functional_unit.
bool is_single_bool_test_cond_expr_units(const unsigned int fu_name) const
return true in case the functional unit implement a cond_expr operation and the condition is a Boolea...
#define NUM_CST_allocation_default_max_fanout_size
The default value used in computation of fanout delay.
bool is_artificial_fu(const unsigned int fu_name) const
Checks if the functional unit is actually an artificial functional unit like: NOP, ENTRY and EXIT.
#define DEBUG_LEVEL_VERBOSE
verbose debugging print is performed.
static bool IsPointerType(const tree_nodeConstRef &type)
Return true if treenode index is a pointer.
#define MULTIPLIER_STD
std::map< unsigned int, unsigned int > get_memory_units() const
Returns the memory units.
ControlStep get_initiation_time(const unsigned int fu_name, const vertex v) const
Returns the initiation time for a given vertex and a given functional unit.
Data structure definition for high-level synthesis flow.
bool is_readonly_memory_unit(const unsigned int fu_name) const
return true in case the functional unit is a read-only memory unit
static void ComputeSsaUses(const tree_nodeRef &, TreeNodeMap< size_t > &uses)
recursively compute the references to the ssa_name variables used in a statement
void print(std::ostream &os) const
Datastructure to represent memory information in high-level synthesis.
uint32_t exp
std::map< unsigned int, unsigned int > nports_map
define the number of ports associated with the functional unit
Class specification of the manager of the tree structures extracted from the raw file.
HLS specialization of generic_device.
std::string get_library(const std::string &Name) const
Return the higher priority library where the given component is stored.
static bool is_an_array(const tree_managerConstRef &TM, const unsigned int index)
Return if treenode index is an array or it is equivalent to an array (record recursively having a sin...
unsigned int max_number_of_resources(const vertex v) const
Computes the maximum number of resources implementing the operation associated with the vertex v...
std::map< unsigned int, unsigned int > memory_units
map between memory units and the associated variables
double EstimateControllerDelay() const
estimate the delay of the controller in straightforward mode
double get_execution_time(const unsigned int fu_name, const vertex v, const OpGraphConstRef g) const
Returns the execution time for a given vertex and a given functional unit.
static bool IsRealType(const tree_nodeConstRef &type)
Return true if the treenode is of real type.
unsigned int get_number_fu_types() const
Returns the number of functional units types.
refcount< const BehavioralHelper > BehavioralHelperConstRef
int sl
Definition: adpcm.c:105
static void get_array_dim_and_bitsize(const tree_managerConstRef &TM, const unsigned int index, std::vector< unsigned long long > &dims, unsigned long long &elts_bitsize)
Return the dimension of the array.
unsigned int GetFuType(const unsigned int operation) const
Return the functional unit type used to execute an operation.
#define MAX_MUX_N_INPUTS
CustomSet< unsigned int > GetZeroDistanceOperations(const unsigned int statement_index) const
Return the set of operations with zero time distance from source.
#define SF_FFDATA_CONVERTER_32_64_STD
#define THROW_ASSERT(cond, str_expr)
helper function used to check an assert and if needed to throw an error in a standard way ...
Definition: exceptions.hpp:289

Generated on Mon Feb 12 2024 13:02:54 for PandA-2024.02 by doxygen 1.8.13