PandA-2024.02
parametric_list_based.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  */
44 
45 #include "ASLAP.hpp"
46 #include "Parameter.hpp"
47 #include "allocation.hpp"
49 #include "basic_block.hpp"
50 #include "behavioral_helper.hpp"
51 #include "call_graph_manager.hpp"
52 #include "cpu_time.hpp"
53 #include "design_flow_graph.hpp"
54 #include "design_flow_manager.hpp"
55 #include "exceptions.hpp"
56 #include "fileIO.hpp"
57 #include "fu_binding.hpp"
58 #include "function_behavior.hpp"
60 #include "functions.hpp"
61 #include "hls.hpp"
62 #include "hls_constraints.hpp"
63 #include "memory.hpp"
64 #include "schedule.hpp"
65 #include "string_manipulation.hpp"
66 #include "structural_objects.hpp"
67 #include "technology_node.hpp"
68 #include "tree_basic_block.hpp"
69 #include "tree_helper.hpp"
70 #include "tree_manager.hpp"
71 #include "tree_node.hpp"
72 #include "utility.hpp"
73 #include "xml_document.hpp"
74 
75 #include <utility>
76 
77 #if !HAVE_UNORDERED
79  : priority(std::move(_priority)), op_graph(_op_graph)
80 {
81 }
82 
83 bool PrioritySorter::operator()(const vertex x, const vertex y) const
84 {
85  const auto x_priority = (*priority)(x);
86  const auto y_priority = (*priority)(y);
87  if(x_priority != y_priority)
88  {
89  return x_priority > y_priority;
90  }
91  return GET_NAME(op_graph, x) < GET_NAME(op_graph, y);
92 }
93 #endif
94 
100 {
101  private:
105 
106  public:
113  bool operator()(const vertex& a, const vertex& b) const
114  {
115  return order.find(a)->second < order.find(b)->second ||
116  (order.find(a)->second == order.find(b)->second && GET_NAME(op_graph, a) < GET_NAME(op_graph, b));
117  }
118 
124  cs_ordering_functor(const OpVertexMap<double>& o, const OpGraphConstRef& opGraph) : order(o), op_graph(opGraph)
125  {
126  }
127 
131  ~cs_ordering_functor() = default;
132 };
133 
138 {
139  private:
142 
143  public:
150  bool operator()(const unsigned int& a, const unsigned int& b) const
151  {
152  unsigned char wm_a = all->is_indirect_access_memory_unit(a) ? 1 : 0;
153  unsigned char wm_b = all->is_indirect_access_memory_unit(b) ? 1 : 0;
154  double we_a = all->get_worst_execution_time(a);
155  double we_b = all->get_worst_execution_time(b);
156  double wa_a = all->get_area(a) + all->get_DSPs(a);
157  double wa_b = all->get_area(b) + all->get_DSPs(b);
158 
159  std::string prefix(PROXY_PREFIX);
160  std::string aFunName = all->get_fu_name(a).first + STR(a);
161  std::string bFunName = all->get_fu_name(b).first + STR(b);
162  if(aFunName.find(prefix) != std::string::npos)
163  {
164  aFunName = aFunName.substr(prefix.length());
165  }
166  if(bFunName.find(prefix) != std::string::npos)
167  {
168  bFunName = bFunName.substr(prefix.length());
169  }
170 
171  return ((wm_a > wm_b) || (wm_a == wm_b && we_a < we_b) || (wm_a == wm_b && we_a == we_b && wa_a < wa_b) ||
172  (wm_a == wm_b && we_a == we_b && wa_a == wa_b && aFunName < bFunName));
173  }
174 
180  {
181  }
182 
186  ~resource_ordering_functor() = default;
187 };
188 
192 class compare_vertex_by_name : std::binary_function<vertex, vertex, bool>
193 {
195 
196  public:
202  explicit compare_vertex_by_name(const OpGraphConstRef& G) : op_graph(G)
203  {
204  }
205 
206  bool operator()(const vertex& a, const vertex& b) const
207  {
208  return GET_NAME(op_graph, a) < GET_NAME(op_graph, b);
209  }
210 };
211 
215 class edge_integer_order_by_map : std::binary_function<vertex, vertex, bool>
216 {
217  private:
219  const std::map<vertex, unsigned int>& ref;
220 
222 #if HAVE_ASSERTS
223  const graph* g;
224 #endif
225 
226  public:
232  edge_integer_order_by_map(const std::map<vertex, unsigned int>& _ref, const graph*
233 #if HAVE_ASSERTS
234  _g)
235  : ref(_ref), g(_g)
236 #else
237  )
238  : ref(_ref)
239 #endif
240  {
241  }
242 
249  bool operator()(const std::pair<std::pair<vertex, vertex>, unsigned int>& x,
250  const std::pair<std::pair<vertex, vertex>, unsigned int>& y) const
251  {
252  THROW_ASSERT(ref.find(x.first.first) != ref.end(),
253  "Vertex " + GET_NAME(g, x.first.first) + " is not in topological_sort");
254  THROW_ASSERT(ref.find(y.first.first) != ref.end(),
255  "Vertex " + GET_NAME(g, y.first.first) + " is not in topological_sort");
256  THROW_ASSERT(ref.find(x.first.second) != ref.end(),
257  "Vertex " + GET_NAME(g, x.first.second) + " is not in topological_sort");
258  THROW_ASSERT(ref.find(y.first.second) != ref.end(),
259  "Vertex " + GET_NAME(g, y.first.second) + " is not in topological_sort");
260  if(ref.find(x.first.first)->second != ref.find(y.first.first)->second)
261  {
262  return ref.find(x.first.first)->second < ref.find(y.first.first)->second;
263  }
264  else if(ref.find(x.first.second)->second != ref.find(y.first.second)->second)
265  {
266  return ref.find(x.first.second)->second < ref.find(y.first.second)->second;
267  }
268  else
269  {
270  return x.second < y.second;
271  }
272  }
273 };
274 
275 static bool check_if_is_live_in_next_cycle(const std::set<vertex, cs_ordering_functor>& live_vertices,
276  const ControlStep current_cycle, const OpVertexMap<double>& ending_time,
277  double clock_cycle)
278 {
279  auto live_vertex_it = live_vertices.begin();
280  while(live_vertex_it != live_vertices.end())
281  {
282  if(ending_time.find(*live_vertex_it)->second > (from_strongtype_cast<double>(current_cycle) + 1) * clock_cycle)
283  {
284  return true;
285  }
286  ++live_vertex_it;
287  }
288  return false;
289 }
290 
292  const ParametricListBased_Metric _parametric_list_based_metric)
293  : parametric_list_based_metric(_parametric_list_based_metric)
294 {
295 }
296 
298 {
300  {
302  return "DynamicMobility";
304  return "StaticFixed";
306  return "StaticMobility";
307  default:
308  THROW_UNREACHABLE("");
309  }
310  return "";
311 }
312 
314 {
315  return GetKindText();
316 }
317 
319  unsigned int _funId, const DesignFlowManagerConstRef _design_flow_manager,
320  const HLSFlowStepSpecializationConstRef _hls_flow_step_specialization)
321  : Scheduling(_parameters, _HLSMgr, _funId, _design_flow_manager, HLSFlowStep_Type::LIST_BASED_SCHEDULING,
322  _hls_flow_step_specialization ?
323  _hls_flow_step_specialization :
326  _parameters->getOption<unsigned int>(OPT_scheduling_priority))))),
329  ending_time(OpGraphConstRef()),
330  clock_cycle(0.0)
331 {
332  debug_level = parameters->get_class_debug_level(GET_CLASS(*this));
333 }
334 
336 
338 {
340  const FunctionBehaviorConstRef FB = HLSMgr->CGetFunctionBehavior(funId);
342 }
343 
344 static bool has_element_in_common(const std::set<std::string>& set1, const std::set<std::string>& set2)
345 {
346  auto first1 = set1.begin(), last1 = set1.end(), first2 = set2.begin(), last2 = set2.end();
347  while(first1 != last1 and first2 != last2)
348  {
349  if(*first1 < *first2)
350  {
351  ++first1;
352  }
353  else if(*first2 < *first1)
354  {
355  ++first2;
356  }
357  else
358  {
359  return true;
360  }
361  }
362  return false;
363 }
364 
366  const CustomUnorderedSet<vertex>& operations, const vertex& current_vertex, ControlStep current_cycle,
367  double& current_starting_time, double& current_ending_time, double& current_stage_period,
368  CustomMap<std::pair<unsigned int, unsigned int>, double>& local_connection_map, double current_cycle_starting_time,
369  double current_cycle_ending_time, double setup_hold_time, double& phi_extra_time, double scheduling_mux_margins,
370  bool unbounded, bool RWFunctions, bool LoadStoreOp, const std::set<std::string>& proxy_functions_used,
371  bool cstep_has_RET_conflict, unsigned int fu_type, const vertex2obj<ControlStep>& current_ASAP,
372  const fu_bindingRef res_binding, const ScheduleRef schedule, bool& predecessorsCond, bool& pipeliningCond,
373  bool& cannotBeChained0, bool& chainingRetCond, bool& cannotBeChained1, bool& asyncCond, bool& cannotBeChained2,
374  bool& cannotBeChained3, bool& MultiCond0, bool& MultiCond1, bool& LoadStoreFunctionConflict,
375  bool& FunctionLoadStoreConflict, bool& proxyFunCond, bool unbounded_RW, bool seeMulticycle)
376 {
377  predecessorsCond = current_ASAP.find(current_vertex) != current_ASAP.end() and
378  current_ASAP.find(current_vertex)->second > current_cycle;
379  if(predecessorsCond)
380  {
381  return;
382  }
383  compute_starting_ending_time_asap(operations, current_vertex, fu_type, current_cycle, current_starting_time,
384  current_ending_time, current_stage_period, cannotBeChained1, res_binding, schedule,
385  phi_extra_time, setup_hold_time, local_connection_map);
386  const auto complex_op = (current_ending_time - current_starting_time) > setup_hold_time;
387  const auto is_pipelined = HLS->allocation_information->get_initiation_time(fu_type, current_vertex) != 0;
388  const auto n_cycles = HLS->allocation_information->get_cycles(fu_type, current_vertex, flow_graph);
389  pipeliningCond = is_pipelined and (current_starting_time > current_cycle_starting_time) and
390  ((current_stage_period + current_starting_time + setup_hold_time + phi_extra_time +
391  (complex_op ? scheduling_mux_margins : 0) >
392  (current_cycle_ending_time) ||
393  unbounded));
394  if(pipeliningCond)
395  {
396  return;
397  }
398  const auto curr_vertex_type = GET_TYPE(flow_graph, current_vertex);
399  cannotBeChained0 =
400  (current_starting_time >= current_cycle_ending_time) ||
401  ((!is_pipelined && !(curr_vertex_type & TYPE_RET) && n_cycles == 0 &&
402  current_starting_time > (current_cycle_starting_time + EPSILON)) &&
403  current_ending_time + setup_hold_time + phi_extra_time + (complex_op ? scheduling_mux_margins : 0) >
404  current_cycle_ending_time);
405  if(cannotBeChained0)
406  {
407  return;
408  }
409  chainingRetCond = (unbounded || cstep_has_RET_conflict) && (curr_vertex_type & TYPE_RET);
410  if(chainingRetCond)
411  {
412  return;
413  }
414  if(cannotBeChained1)
415  {
416  return;
417  }
418  asyncCond = (current_starting_time > (EPSILON + current_cycle_starting_time)) and (curr_vertex_type & TYPE_LOAD) and
421  (!HLS->Param->isOption(OPT_rom_duplication) || !parameters->getOption<bool>(OPT_rom_duplication))) and
422  ((HLSMgr->Rmem->get_maximum_references(HLS->allocation_information->is_memory_unit(fu_type) ?
426  if(asyncCond)
427  {
428  return;
429  }
430  cannotBeChained2 =
431  (current_starting_time > (current_cycle_starting_time)) && !parameters->getOption<bool>(OPT_chaining);
432  if(cannotBeChained2)
433  {
434  return;
435  }
436  MultiCond0 =
437  (n_cycles > 1 && (unbounded_RW || unbounded)) ||
438  (seeMulticycle && !HLS->allocation_information->is_operation_bounded(flow_graph, current_vertex, fu_type)) ||
439  ((!is_pipelined && n_cycles > 0 && current_starting_time > (current_cycle_starting_time)) &&
440  current_ending_time - (n_cycles - 1) * clock_cycle + setup_hold_time + phi_extra_time +
441  (complex_op ? scheduling_mux_margins : 0) >
442  current_cycle_ending_time);
443  if(MultiCond0)
444  {
445  return;
446  }
447  MultiCond1 = current_ending_time + setup_hold_time + phi_extra_time + (complex_op ? scheduling_mux_margins : 0) >
448  current_cycle_ending_time &&
449  unbounded && HLS->allocation_information->is_operation_bounded(flow_graph, current_vertex, fu_type);
450  if(MultiCond1)
451  {
452  return;
453  }
454  const auto curr_node = flow_graph->CGetOpNodeInfo(current_vertex);
455  const auto curr_node_name = curr_node->GetOperation();
456  const auto fid = curr_node->called.empty() ? 0U : *curr_node->called.begin();
457  if(!HLSMgr->CGetCallGraphManager()->GetRootFunctions().count(fid))
458  {
459  LoadStoreFunctionConflict = (curr_vertex_type & (TYPE_LOAD | TYPE_STORE)) && RWFunctions;
460  if(LoadStoreFunctionConflict)
461  {
462  return;
463  }
464  FunctionLoadStoreConflict =
465  (curr_vertex_type & TYPE_EXTERNAL) && (curr_vertex_type & TYPE_RW) && (LoadStoreOp || RWFunctions);
466  if(FunctionLoadStoreConflict)
467  {
468  return;
469  }
470  proxyFunCond = (curr_vertex_type & TYPE_EXTERNAL) &&
471  (proxy_functions_used.count(curr_node_name) ||
472  (reachable_proxy_functions.count(curr_node_name) &&
473  has_element_in_common(proxy_functions_used, reachable_proxy_functions.at(curr_node_name))));
474  if(proxyFunCond)
475  {
476  return;
477  }
478  }
479  cannotBeChained3 = (curr_vertex_type & TYPE_EXTERNAL) && !is_pipelined && n_cycles > 1 &&
481  if(cannotBeChained3)
482  {
483  bool is_chained = false;
484  BOOST_FOREACH(EdgeDescriptor e, boost::in_edges(current_vertex, *flow_graph))
485  {
486  const auto from_vertex = boost::source(e, *flow_graph);
487  if(operations.find(from_vertex) == operations.end())
488  {
489  continue;
490  }
491  if(GET_TYPE(flow_graph, from_vertex) & (TYPE_PHI | TYPE_VPHI))
492  {
494  "---Skipping phi predecessor " + GET_NAME(flow_graph, from_vertex));
495  continue;
496  }
497  const auto cs_prev = schedule->get_cstep(from_vertex).second;
498  if(cs_prev == current_cycle)
499  {
500  is_chained = true;
501  break;
502  }
503  }
504  cannotBeChained3 = false;
505  if(is_chained)
506  {
507  cannotBeChained3 = current_ending_time - (n_cycles - 1) * clock_cycle + setup_hold_time + phi_extra_time +
509  current_cycle_ending_time;
510  }
511  }
512  if(cannotBeChained3)
513  {
514  return;
515  }
516 }
517 
518 const double parametric_list_based::EPSILON = 0.000000001;
519 
520 #define CTRL_STEP_MULTIPLIER 1000
521 
522 void parametric_list_based::exec(const OpVertexSet& Operations, ControlStep current_cycle)
523 {
524  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "Executing parametric_list_based::exec...");
525  THROW_ASSERT(Operations.size(), "At least one vertex is expected");
526  const FunctionBehaviorConstRef FB = HLSMgr->CGetFunctionBehavior(funId);
527  const OpGraphConstRef op_graph = FB->CGetOpGraph(FunctionBehavior::CFG);
528  const auto top_function_ids = HLSMgr->CGetCallGraphManager()->GetRootFunctions();
529  const unsigned int return_type_index = FB->CGetBehavioralHelper()->GetFunctionReturnType(funId);
530  auto registering_output_p = top_function_ids.find(funId) != top_function_ids.end() && return_type_index &&
531  parameters->getOption<std::string>(OPT_registered_inputs) == "top";
532  CustomUnorderedSet<vertex> operations;
533  for(auto op : Operations)
534  {
535  operations.insert(op);
536  }
537 
539  const ScheduleRef schedule = HLS->Rsch;
540 
542  vertex2obj<ControlStep> current_ASAP;
543 
545  const fu_bindingRef res_binding = HLS->Rfu;
546 
548  vertex2obj<size_t> scheduled_predecessors;
549 
550  double clock_period_resource_fraction = HLS->HLS_C->get_clock_period_resource_fraction();
551 
552  double scheduling_mux_margins =
553  parameters->getOption<double>(OPT_scheduling_mux_margins) * HLS->allocation_information->mux_time_unit(32);
554 
556  clock_cycle = clock_period_resource_fraction * HLS->HLS_C->get_clock_period();
557  if(clock_cycle < scheduling_mux_margins)
558  {
559  THROW_ERROR("Mux margins too constrained");
560  }
561 
563  double setup_hold_time = HLS->allocation_information->get_setup_hold_time();
564 
567  std::set<unsigned int, resource_ordering_functor> ready_resources(r_functor);
568 
570  OpVertexSet ready_vertices(op_graph);
571 
573  cs_ordering_functor et_order(ending_time, op_graph);
574  std::set<vertex, cs_ordering_functor> live_vertices(et_order);
575 
577  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, " Selecting the type of the graph...");
578 
579  if(speculation)
580  {
581  flow_graph = FB->CGetOpGraph(FunctionBehavior::SG);
583  }
584  else
585  {
586  flow_graph = FB->CGetOpGraph(FunctionBehavior::FLSAODG);
588  }
589 
591  size_t operations_number = Operations.size();
592 
593  // long int cpu_time;
595  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, " Computing asap and alap...");
596  // START_TIME(cpu_time);
597  ASLAPRef aslap;
600  {
601  aslap = ASLAPRef(new ASLAP(HLSMgr, HLS, speculation, operations, parameters, CTRL_STEP_MULTIPLIER));
602  if(HLS->Rsch->num_scheduled() == 0)
603  {
604  aslap->compute_ASAP();
605  aslap->compute_ALAP(ASLAP::ALAP_fast);
606  }
607  else
608  {
609  aslap->compute_ASAP(HLS->Rsch);
610  auto est_upper_bound = ControlStep(static_cast<unsigned int>(operations_number));
611  aslap->compute_ALAP(ASLAP::ALAP_with_partial_scheduling, HLS->Rsch, nullptr, est_upper_bound);
612  }
613  }
614  // STOP_TIME(cpu_time);
615  // if(output_level >= OUTPUT_LEVEL_VERY_PEDANTIC)
616  // INDENT_OUT_MEX(OUTPUT_LEVEL_VERY_PEDANTIC, output_level, "---Time to perform ASAP+ALAP scheduling: " +
617  // print_cpu_time(cpu_time) + " seconds");
618 
619  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, " Computing free input vertices...");
622  for(auto operation : Operations)
623  {
625  if(schedule->is_scheduled(operation))
626  {
627  live_vertices.insert(operation);
628  }
629  else
630  {
632  InEdgeIterator ei, ei_end;
633  for(boost::tie(ei, ei_end) = boost::in_edges(operation, *flow_graph); ei != ei_end; ei++)
634  {
635  vertex source = boost::source(*ei, *flow_graph);
636  if(operations.find(source) != operations.end() && !schedule->is_scheduled(source))
637  {
638  break;
639  }
640  }
641  if(ei == ei_end)
642  {
643  ready_vertices.insert(operation);
644  }
645  }
646  }
647 
648  THROW_ASSERT(ready_vertices.size(), "At least one vertex is expected");
649  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, " Number of vertices: " + STR(ready_vertices.size()));
650 
652  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, " Setting priority...");
653  refcount<priority_data<int>> Priority;
655  {
658  break;
660  {
661  Priority =
663  break;
664  }
666  {
668  CustomMap<std::string, int> string_priority_value = HLS->HLS_C->get_scheduling_priority();
669  VertexIterator ki, ki_end;
670  for(auto op : Operations)
671  {
672  priority_value[op] = string_priority_value[GET_NAME(flow_graph, op)];
673  }
674  Priority = refcount<priority_data<int>>(new priority_fixed(priority_value));
675  break;
676  }
677  default:
678  THROW_UNREACHABLE("");
679  }
680 
682  unsigned int n_resources = HLS->allocation_information->get_number_fu_types();
683 #if HAVE_UNORDERED
684  priority_compare_functor<int> priority_functors(Priority);
685  PriorityQueues priority_queues(n_resources, priority_functors);
686 #else
687  PriorityQueues priority_queues(n_resources, std::set<vertex, PrioritySorter>(PrioritySorter(Priority, flow_graph)));
688 #endif
689  unsigned int cstep_vuses_ARRAYs = 0;
690  unsigned int cstep_vuses_others = 0;
691  bool cstep_has_RET_conflict = false;
692 
693  OpVertexSet::const_iterator rv, rv_end = ready_vertices.end();
694 
695  for(rv = ready_vertices.begin(); rv != rv_end; ++rv)
696  {
697  add_to_priority_queues(priority_queues, ready_resources, *rv);
698  }
699 
700  const auto TM = HLSMgr->get_tree_manager();
701  auto fnode = TM->get_tree_node_const(funId);
702  auto fd = GetPointer<function_decl>(fnode);
703  const auto fname = tree_helper::GetMangledFunctionName(fd);
705  if(HLSMgr->design_interface_io.find(fname) != HLSMgr->design_interface_io.end())
706  {
707  for(const auto& bb2arg2stmtsR : HLSMgr->design_interface_io.at(fname))
708  {
709  for(const auto& arg2stms : bb2arg2stmtsR.second)
710  {
711  if(arg2stms.second.size() > 0)
712  {
713  for(const auto& stmt : arg2stms.second)
714  {
715  const auto op_it = flow_graph->CGetOpGraphInfo()->tree_node_to_operation.find(stmt);
716  if(op_it != flow_graph->CGetOpGraphInfo()->tree_node_to_operation.end())
717  {
718  RW_stmts.insert(op_it->second);
719  }
720  }
721  }
722  }
723  }
724  }
725 
726  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, " Starting scheduling...");
727  unsigned int already_sch = schedule->num_scheduled();
728  while((schedule->num_scheduled() - already_sch) != operations_number)
729  {
730  bool unbounded = false;
731  bool RWFunctions = false;
732  bool unbounded_RW = false;
733  bool LoadStoreOp = false;
734  bool seeMulticycle = false;
735  unsigned int n_scheduled_ops = 0;
736  const auto current_cycle_starting_time = from_strongtype_cast<double>(current_cycle) * clock_cycle;
737  const auto current_cycle_ending_time = from_strongtype_cast<double>(current_cycle + 1) * clock_cycle;
738  cstep_has_RET_conflict =
739  ((schedule->num_scheduled() - already_sch) != operations_number - 1) ? registering_output_p : false;
740  std::set<std::string> proxy_functions_used;
742  " schedule->num_scheduled() " + std::to_string(schedule->num_scheduled()));
743  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, " already_sch " + std::to_string(already_sch));
745  " operations_number " + std::to_string(operations_number));
747  " Scheduling in control step " + STR(current_cycle) +
748  " (Time: " + STR(current_cycle_starting_time) + ")");
753 
757 
759  auto live_vertex_it = live_vertices.begin();
760  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, " Considering live vertices...");
761  while(live_vertex_it != live_vertices.end())
762  {
763  if(ending_time.find(*live_vertex_it)->second > current_cycle_ending_time)
764  {
765  seeMulticycle = true;
766  }
767  if(ending_time.find(*live_vertex_it)->second <= current_cycle_starting_time)
768  {
770  " Vertex " + GET_NAME(flow_graph, *live_vertex_it) + " dies");
771  live_vertices.erase(*live_vertex_it);
772  live_vertex_it = live_vertices.begin();
773  }
774  else
775  {
776  auto live_vertex_type = GET_TYPE(flow_graph, *live_vertex_it);
777  if(live_vertex_type & TYPE_STORE)
778  {
779  cstep_has_RET_conflict = true;
780  }
781  if(live_vertex_type & (TYPE_LOAD | TYPE_STORE))
782  {
783  LoadStoreOp = true;
784  }
785  if((live_vertex_type & TYPE_EXTERNAL) && (live_vertex_type & TYPE_RW) &&
786  RW_stmts.find(*live_vertex_it) == RW_stmts.end())
787  {
788  RWFunctions = true;
789  }
790  const auto II = HLS->allocation_information->get_initiation_time(res_binding->get_assign(*live_vertex_it),
791  *live_vertex_it);
792  if(FB->is_simple_pipeline() && (II > 1 || II == 0))
793  {
794  auto lat = ending_time[*live_vertex_it] - starting_time[*live_vertex_it];
795  THROW_ERROR("Timing of Vertex " + GET_NAME(flow_graph, *live_vertex_it) +
796  " is not compatible with II=1.\nActual vertex latency is " + STR(lat) +
797  " greater than the clock period");
798  }
799 
800  if(II == 0u ||
801  current_cycle < (II + static_cast<unsigned int>(floor(starting_time[*live_vertex_it] / clock_cycle))))
802  {
803  bool schedulable;
804  if(used_resources.find(res_binding->get_assign(*live_vertex_it)) == used_resources.end())
805  {
806  used_resources[res_binding->get_assign(*live_vertex_it)] = 0;
807  }
808  schedulable = BB_update_resources_use(used_resources[res_binding->get_assign(*live_vertex_it)],
809  res_binding->get_assign(*live_vertex_it));
810  if(!schedulable)
811  {
812  THROW_ERROR("Unfeasible scheduling");
813  }
814  }
816  " Vertex " + GET_NAME(flow_graph, *live_vertex_it) + " lives until " +
817  STR(ending_time.find(*live_vertex_it)->second));
818  ++live_vertex_it;
819  }
820  }
821 
822  for(unsigned int fu_type = 0; fu_type < n_resources; ++fu_type)
823  {
824  if(priority_queues[fu_type].size())
825  {
826  ready_resources.insert(fu_type);
827  }
828  }
829 
830  CustomMap<unsigned int, OpVertexSet> postponed_resources;
831  CustomMap<unsigned int, OpVertexSet> restarted_resources;
832  bool do_again;
833 
834  auto prev_scheduled = schedule->num_scheduled();
835  do
836  {
837  do_again = false;
838  while(ready_resources.size())
839  {
840  const auto fu_type = *ready_resources.begin();
841  ready_resources.erase(ready_resources.begin());
842  THROW_ASSERT(fu_type != static_cast<unsigned>(-1), "");
843 
845  "-->Considering functional unit type " + STR(fu_type) + "(" +
846  HLS->allocation_information->get_fu_name(fu_type).first + "-" +
847  HLS->allocation_information->get_fu_name(fu_type).second + ")" + " at clock cycle " +
848  STR(current_cycle));
849 
850  auto& queue = priority_queues[fu_type];
852  while(queue.size())
853  {
854 #if HAVE_UNORDERED
855  auto current_vertex = queue.top();
856 #else
857  auto current_vertex = *(queue.begin());
858 #endif
860  "---First operation ready for this unit is " + GET_NAME(flow_graph, current_vertex));
861 #if HAVE_UNORDERED
862  queue.pop();
863 #else
864  queue.erase(queue.begin());
866  "-->Other ready operations (" + STR(queue.size()) + ") are:");
867 #ifndef NDEBUG
868  for(const auto temp_operation : queue)
869  {
871  "---" + GET_NAME(flow_graph, temp_operation) + ": " +
872  STR((*Priority)(temp_operation)));
873  }
874 #endif
876 #endif
877  if(schedule->is_scheduled(current_vertex))
879  {
880  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, " Already scheduled");
882  continue;
883  }
886  if(used_resources.find(fu_type) == used_resources.end())
887  {
888  used_resources[fu_type] = 0;
889  }
890  bool schedulable = used_resources.at(fu_type) != HLS->allocation_information->get_number_fu(fu_type);
891  if(!schedulable)
892  {
893  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---No free resource");
894  if(black_list.find(fu_type) == black_list.end())
895  {
896  black_list.emplace(fu_type, OpVertexSet(flow_graph));
897  }
898  black_list.at(fu_type).insert(current_vertex);
899  continue;
900  }
902  bool postponed = false;
903  auto curr_vertex_type = GET_TYPE(flow_graph, current_vertex);
904  if(curr_vertex_type & (TYPE_LOAD | TYPE_STORE))
905  {
906  bool is_array = HLS->allocation_information->is_direct_access_memory_unit(fu_type);
907  unsigned var = is_array ? (HLS->allocation_information->is_memory_unit(fu_type) ?
910  0;
911  if(is_array && cstep_vuses_others && !HLSMgr->Rmem->is_private_memory(var))
912  {
913  postponed = true;
914  }
915  else if(!is_array && cstep_vuses_ARRAYs)
916  {
917  postponed = true;
918  }
919  /*
920  if(!postponed && !cstep_vuses_ARRAYs && !cstep_vuses_others)
921  {
922  for(auto cur_fu_type: ready_resources)
923  {
924  if(HLS->allocation_information->is_direct_access_memory_unit(cur_fu_type) ||
925  HLS->allocation_information->is_indirect_access_memory_unit(cur_fu_type))
926  {
927  vertex cand_vertex = priority_queues[cur_fu_type].top();
928  if((*Priority)(current_vertex)<(*Priority)(cand_vertex))
929  postponed = true;
930  }
931  }
932  }*/
933  }
934  if(postponed)
935  {
937  " MEMORY_CTRL cannot run together with BRAM direct accesses " +
938  GET_NAME(flow_graph, current_vertex) + " mapped on " +
939  HLS->allocation_information->get_fu_name(fu_type).first + "at cstep " +
940  STR(current_cycle));
941  if(black_list.find(fu_type) == black_list.end())
942  {
943  black_list.emplace(fu_type, OpVertexSet(flow_graph));
944  }
945  black_list.at(fu_type).insert(current_vertex);
946  continue;
947  }
948 
949  bool is_live = check_if_is_live_in_next_cycle(live_vertices, current_cycle, ending_time, clock_cycle);
950  THROW_ASSERT(!(curr_vertex_type & (TYPE_WHILE | TYPE_FOR)), "not expected operation type");
952  if((curr_vertex_type & (TYPE_IF | TYPE_RET | TYPE_SWITCH | TYPE_MULTIIF | TYPE_GOTO)) &&
953  (unbounded || unbounded_RW || is_live))
954  {
955  if(black_list.find(fu_type) == black_list.end())
956  {
957  black_list.emplace(fu_type, OpVertexSet(flow_graph));
958  }
959  black_list.at(fu_type).insert(current_vertex);
961  " Scheduling of Control Vertex " + GET_NAME(flow_graph, current_vertex) +
962  " postponed to the next cycle");
963  continue;
964  }
965  if((curr_vertex_type & (TYPE_IF | TYPE_RET | TYPE_SWITCH | TYPE_MULTIIF | TYPE_GOTO)) &&
966  ((schedule->num_scheduled() - already_sch) != operations_number - 1))
967  {
968  if(postponed_resources.find(fu_type) == postponed_resources.end())
969  {
970  postponed_resources.emplace(fu_type, OpVertexSet(flow_graph));
971  }
972  postponed_resources.at(fu_type).insert(current_vertex);
974  " Scheduling of Control Vertex " + GET_NAME(flow_graph, current_vertex) +
975  " postponed ");
976  continue;
977  }
978 
979  if((curr_vertex_type & TYPE_RET) &&
980  ((schedule->num_scheduled() - already_sch) == operations_number - 1) && n_scheduled_ops != 0 &&
981  registering_output_p)
982  {
983  if(black_list.find(fu_type) == black_list.end())
984  {
985  black_list.emplace(fu_type, OpVertexSet(flow_graph));
986  }
987  black_list.at(fu_type).insert(current_vertex);
988 
990  " Scheduling of Control Vertex " + GET_NAME(flow_graph, current_vertex) +
991  " postponed to the next cycle to register the output");
992  continue;
993  }
994  if(!HLS->allocation_information->is_operation_bounded(flow_graph, current_vertex, fu_type) &&
995  RW_stmts.find(current_vertex) == RW_stmts.end() && (unbounded_RW || is_live))
996  {
997  if(black_list.find(fu_type) == black_list.end())
998  {
999  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1000  }
1001  black_list.at(fu_type).insert(current_vertex);
1003  " Scheduling of unbounded " + GET_NAME(flow_graph, current_vertex) +
1004  " postponed to the next cycle");
1005  continue;
1006  }
1007  if(!HLS->allocation_information->is_operation_bounded(flow_graph, current_vertex, fu_type) &&
1008  RW_stmts.find(current_vertex) != RW_stmts.end() && unbounded)
1009  {
1010  if(black_list.find(fu_type) == black_list.end())
1011  {
1012  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1013  }
1014  black_list.at(fu_type).insert(current_vertex);
1016  " Scheduling of unbounded RW interface " +
1017  GET_NAME(flow_graph, current_vertex) + " postponed to the next cycle");
1018  continue;
1019  }
1020 
1022  double current_starting_time;
1023 
1025  double current_ending_time;
1026 
1028  double current_stage_period;
1029 
1030  double phi_extra_time;
1031  CustomMap<std::pair<unsigned int, unsigned int>, double> local_connection_map;
1032 
1033  bool predecessorsCond = false, pipeliningCond = false, cannotBeChained0 = false, chainingRetCond = false,
1034  cannotBeChained1 = false, asyncCond = false, cannotBeChained2 = false, cannotBeChained3 = false,
1035  MultiCond0 = false, MultiCond1 = false, LoadStoreFunctionConflict = false,
1036  FunctionLoadStoreConflict = false, proxyFunCond = false;
1037 
1039  operations, current_vertex, current_cycle, current_starting_time, current_ending_time,
1040  current_stage_period, local_connection_map, current_cycle_starting_time, current_cycle_ending_time,
1041  setup_hold_time, phi_extra_time, scheduling_mux_margins, unbounded, RWFunctions, LoadStoreOp,
1042  proxy_functions_used, cstep_has_RET_conflict, fu_type, current_ASAP, res_binding, schedule,
1043  predecessorsCond, pipeliningCond, cannotBeChained0, chainingRetCond, cannotBeChained1, asyncCond,
1044  cannotBeChained2, cannotBeChained3, MultiCond0, MultiCond1, LoadStoreFunctionConflict,
1045  FunctionLoadStoreConflict, proxyFunCond, unbounded_RW, seeMulticycle);
1046 
1048  if(predecessorsCond)
1049  {
1051  " Depends on a live operation");
1052  if(black_list.find(fu_type) == black_list.end())
1053  {
1054  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1055  }
1056  black_list.at(fu_type).insert(current_vertex);
1057  continue;
1058  }
1059 
1060  if(pipeliningCond)
1061  {
1063  " Pipelined unit cannot be chained: starting time is " +
1064  std::to_string(current_starting_time) + " stage period is " +
1065  std::to_string(current_stage_period));
1066  if(black_list.find(fu_type) == black_list.end())
1067  {
1068  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1069  }
1070  black_list.at(fu_type).insert(current_vertex);
1071  continue;
1072  }
1073  else if(cannotBeChained0)
1074  {
1076  " It cannot be chained: starting time is " +
1077  std::to_string(current_starting_time) + " ending time is " +
1078  std::to_string(current_ending_time));
1079  if(black_list.find(fu_type) == black_list.end())
1080  {
1081  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1082  }
1083  black_list.at(fu_type).insert(current_vertex);
1084  continue;
1085  }
1086  else if(chainingRetCond)
1087  {
1088  PRINT_DBG_MEX(
1090  " Chaining of return expression operation is not allowed by construction" +
1091  (unbounded ? std::string("(unbounded)") : std::string("(bounded)")));
1092  if(black_list.find(fu_type) == black_list.end())
1093  {
1094  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1095  }
1096  black_list.at(fu_type).insert(current_vertex);
1097  continue;
1098  }
1099  else if(cannotBeChained1)
1100  {
1102  " Chaining with a store or a load or an unbounded in input is not "
1103  "possible -> starting time " +
1104  std::to_string(current_starting_time) +
1105  " ending time: " + std::to_string(current_ending_time));
1106  if(black_list.find(fu_type) == black_list.end())
1107  {
1108  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1109  }
1110  black_list.at(fu_type).insert(current_vertex);
1111  continue;
1112  }
1113  /*
1114  else if(has_read_cond_with_non_direct_operations)
1115  {
1116  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, " READ_COND or MULTI_READ_COND
1117  cannot be chained with non-direct operations -> starting time " +
1118  std::to_string(current_starting_time) + " ending time: " +
1119  std::to_string(current_ending_time)); if(black_list.find(fu_type) == black_list.end())
1120  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1121  black_list.at(fu_type).insert(current_vertex);
1122  continue;
1123  }*/
1124  else if(asyncCond)
1125  {
1126  PRINT_DBG_MEX(
1128  " Chaining with an asynchronous load is not possible -> starting time " +
1129  std::to_string(current_starting_time) +
1130  " ending time: " + std::to_string(current_ending_time));
1131  if(black_list.find(fu_type) == black_list.end())
1132  {
1133  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1134  }
1135  black_list.at(fu_type).insert(current_vertex);
1136  continue;
1137  }
1138  /*else if((current_starting_time > (current_cycle_starting_time)) && (GET_TYPE(flow_graph, current_v) &
1139  TYPE_STORE) && HLS->allocation_information->is_indirect_access_memory_unit(fu_type))
1140  {
1141  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, " Chaining with a store is not
1142  possible -> starting time " + std::to_string(current_starting_time) + " ending time: "
1143  + std::to_string(current_ending_time)); if(black_list.find(fu_type) ==
1144  black_list.end()) black_list.emplace(fu_type, OpVertexSet(flow_graph));
1145  black_list.at(fu_type).insert(current_vertex);
1146  continue;
1147  }
1148  else if((current_starting_time > (current_cycle_starting_time)) && (curr_vertex_type & TYPE_LOAD) &&
1149  HLS->allocation_information->is_indirect_access_memory_unit(fu_type))
1150  {
1151  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, " Chaining with a load is not
1152  possible -> starting time " + std::to_string(current_starting_time) + " ending time: "
1153  + std::to_string(current_ending_time)); if(black_list.find(fu_type) ==
1154  black_list.end()) black_list.emplace(fu_type, OpVertexSet(flow_graph));
1155  black_list.at(fu_type).insert(current_vertex);
1156  continue;
1157  }*/
1158  else if(cannotBeChained2)
1159  {
1161  " Chaining is possible but not allowed -> starting time " +
1162  std::to_string(current_starting_time) +
1163  " ending time: " + std::to_string(current_ending_time));
1164  if(black_list.find(fu_type) == black_list.end())
1165  {
1166  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1167  }
1168  black_list.at(fu_type).insert(current_vertex);
1169  continue;
1170  }
1171  else if(MultiCond0)
1172  {
1173  PRINT_DBG_MEX(
1175  " First cycle of a Multi-cycles operations does not fit in the first period");
1176  if(black_list.find(fu_type) == black_list.end())
1177  {
1178  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1179  }
1180  black_list.at(fu_type).insert(current_vertex);
1181  continue;
1182  }
1183  else if(MultiCond1)
1184  {
1186  " Multi-cycles operations cannot be scheduled together with unbounded "
1187  "operations");
1188  if(black_list.find(fu_type) == black_list.end())
1189  {
1190  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1191  }
1192  black_list.at(fu_type).insert(current_vertex);
1193  continue;
1194  }
1195  else if(LoadStoreFunctionConflict)
1196  {
1198  " Memory access operations may conflict with function calls");
1199  if(black_list.find(fu_type) == black_list.end())
1200  {
1201  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1202  }
1203  black_list.at(fu_type).insert(current_vertex);
1204  continue;
1205  }
1206  else if(FunctionLoadStoreConflict)
1207  {
1209  " function calls may conflict with memory access operations ");
1210  if(black_list.find(fu_type) == black_list.end())
1211  {
1212  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1213  }
1214  black_list.at(fu_type).insert(current_vertex);
1215  continue;
1216  }
1217  else if(proxyFunCond)
1218  {
1220  " proxy function may conflict with other functions calling the same "
1221  "proxy function ");
1222  if(black_list.find(fu_type) == black_list.end())
1223  {
1224  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1225  }
1226  black_list.at(fu_type).insert(current_vertex);
1227  continue;
1228  }
1229  /*else if(store_in_chaining_with_load_in(current_cycle, current_vertex))
1230  {
1231  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, " Load and store cannot be
1232  chained"); if(black_list.find(fu_type) == black_list.end()) black_list.emplace(fu_type,
1233  OpVertexSet(flow_graph)); black_list.at(fu_type).insert(current_vertex); continue;
1234  }*/
1235  else if(cannotBeChained3)
1236  {
1238  " cannot be chained because critical path of the current function "
1239  "plus the one of the called function are not compatible with the clock ");
1240  if(black_list.find(fu_type) == black_list.end())
1241  {
1242  black_list.emplace(fu_type, OpVertexSet(flow_graph));
1243  }
1244  black_list.at(fu_type).insert(current_vertex);
1245  continue;
1246  }
1247 
1249  ++n_scheduled_ops;
1251  used_resources[fu_type]++;
1252 
1254  if((curr_vertex_type & TYPE_EXTERNAL) && (curr_vertex_type & TYPE_RW) &&
1255  RW_stmts.find(current_vertex) == RW_stmts.end())
1256  {
1257  RWFunctions = true;
1258  }
1259 
1260  if((curr_vertex_type & TYPE_EXTERNAL))
1261  {
1262  auto curr_op_name = flow_graph->CGetOpNodeInfo(current_vertex)->GetOperation();
1263  if(HLSMgr->Rfuns->is_a_proxied_function(curr_op_name))
1264  {
1265  proxy_functions_used.insert(curr_op_name);
1266  }
1267  if(reachable_proxy_functions.find(curr_op_name) != reachable_proxy_functions.end())
1268  {
1269  for(const auto& p : reachable_proxy_functions.at(curr_op_name))
1270  {
1271  proxy_functions_used.insert(p);
1272  }
1273  }
1274  }
1275 
1277  if(!HLS->allocation_information->is_operation_bounded(flow_graph, current_vertex, fu_type) &&
1278  RW_stmts.find(current_vertex) == RW_stmts.end())
1279  {
1281  " " + GET_NAME(flow_graph, current_vertex) + " is unbounded");
1282  THROW_ASSERT(!(is_live), "unexpected case");
1283  double ex_time = HLS->allocation_information->get_execution_time(fu_type, current_vertex, flow_graph);
1284  if(ex_time > clock_cycle)
1285  {
1286  THROW_WARNING("Operation execution time of the unbounded operation is greater than the clock "
1287  "period resource fraction (" +
1288  STR(clock_cycle) + ").\n\tExecution time " + STR(ex_time) + " of " +
1289  GET_NAME(flow_graph, current_vertex) + " of type " +
1290  flow_graph->CGetOpNodeInfo(current_vertex)->GetOperation() +
1291  "\nThis may prevent meeting the timing constraints.\n");
1292  }
1293  unbounded = true;
1294  }
1295  else if(!HLS->allocation_information->is_operation_bounded(flow_graph, current_vertex, fu_type) &&
1296  RW_stmts.find(current_vertex) != RW_stmts.end())
1297  {
1298  unbounded_RW = true;
1299  }
1300  else
1301  {
1303  "---" + GET_NAME(flow_graph, current_vertex) + " is bounded");
1304  }
1306  if((curr_vertex_type & (TYPE_LOAD | TYPE_STORE)))
1307  {
1308  LoadStoreOp = true;
1309  }
1310 
1312  if(curr_vertex_type & (TYPE_LOAD | TYPE_STORE))
1313  {
1314  cstep_has_RET_conflict = (curr_vertex_type & (TYPE_STORE)) != 0;
1315 
1316  bool is_array = HLS->allocation_information->is_direct_access_memory_unit(fu_type);
1317  unsigned var = is_array ? (HLS->allocation_information->is_memory_unit(fu_type) ?
1320  0;
1321  if(!var || !HLSMgr->Rmem->is_private_memory(var))
1322  {
1323  if(HLS->allocation_information->is_direct_access_memory_unit(fu_type) && !cstep_vuses_others)
1324  {
1325  cstep_vuses_ARRAYs = 1;
1326  }
1327  else
1328  {
1329  cstep_vuses_others =
1330  1 + ((parameters->getOption<std::string>(OPT_memory_controller_type) != "D00" &&
1331  parameters->getOption<std::string>(OPT_memory_controller_type) != "D10") ?
1332  1 :
1333  0);
1334  }
1335  }
1336  }
1337  if((curr_vertex_type & TYPE_EXTERNAL) && (curr_vertex_type & TYPE_RW))
1338  {
1339  cstep_has_RET_conflict = true;
1340  }
1343  "---" + GET_NAME(flow_graph, current_vertex) + " scheduled at " +
1344  STR(current_cycle_starting_time));
1345  schedule->set_execution(current_vertex, current_cycle);
1346  starting_time[current_vertex] = current_starting_time;
1347  if(!HLS->allocation_information->is_operation_bounded(flow_graph, current_vertex, fu_type) &&
1348  (current_ending_time + setup_hold_time + phi_extra_time + scheduling_mux_margins >
1349  current_cycle_ending_time))
1350  {
1351  ending_time[current_vertex] = current_cycle_ending_time - setup_hold_time;
1352  }
1353  else
1354  {
1355  ending_time[current_vertex] = current_ending_time;
1356  }
1357  auto current_statement = flow_graph->CGetOpNodeInfo(current_vertex)->GetNodeId();
1358  schedule->starting_times[current_statement] = starting_time[current_vertex];
1359  schedule->ending_times[current_statement] = ending_time[current_vertex];
1360  THROW_ASSERT(ending_time[current_vertex] >= starting_time[current_vertex], "unexpected condition");
1361  THROW_ASSERT(floor(ending_time[current_vertex] / clock_cycle + 0.0001) >=
1362  from_strongtype_cast<double>(current_cycle),
1363  GET_NAME(flow_graph, current_vertex) + " " + STR(ending_time[current_vertex]) + " " +
1364  STR(from_strongtype_cast<double>(current_cycle)));
1365  schedule->set_execution_end(current_vertex,
1366  current_cycle + ControlStep(static_cast<unsigned int>(
1367  floor(ending_time[current_vertex] / clock_cycle) -
1368  from_strongtype_cast<double>(current_cycle))));
1370  if(HLS->allocation_information->is_operation_bounded(flow_graph, current_vertex, fu_type) &&
1371  ending_time[current_vertex] > current_cycle_ending_time)
1372  {
1373  seeMulticycle = true;
1374  }
1375 
1376  for(auto edge_connection_pair : local_connection_map)
1377  {
1378  schedule->AddConnectionTimes(edge_connection_pair.first.first, edge_connection_pair.first.second,
1379  edge_connection_pair.second);
1380  }
1381  if(phi_extra_time > 0.0)
1382  {
1383  schedule->AddConnectionTimes(current_statement, 0, phi_extra_time);
1384  }
1385  ready_vertices.erase(current_vertex);
1386 
1388  if(HLS->HLS_C->has_binding_to_fu(GET_NAME(flow_graph, current_vertex)))
1389  {
1390  res_binding->bind(current_vertex, fu_type, 0);
1391  }
1392  else
1393  {
1394  res_binding->bind(current_vertex, fu_type);
1395  }
1396 
1398  " Current cycles ends at " + STR(current_cycle_ending_time) +
1399  " - operation ends at " + STR(ending_time[current_vertex]));
1400  if(ending_time[current_vertex] > current_cycle_ending_time)
1401  {
1402  live_vertices.insert(current_vertex);
1403  }
1404 
1406  OutEdgeIterator eo, eo_end;
1407 
1408  std::list<std::pair<std::string, vertex>> successors;
1409  for(boost::tie(eo, eo_end) = boost::out_edges(current_vertex, *flow_graph); eo != eo_end; eo++)
1410  {
1412  if(operations.find(target) != operations.end())
1413  {
1414  successors.push_back(std::make_pair(GET_NAME(flow_graph, target), target));
1415  }
1416  }
1417  // successors.sort();
1418 
1419  for(auto& successor : successors)
1420  {
1421  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Considering successor " + successor.first);
1422  scheduled_predecessors[successor.second]++;
1423  if(current_ASAP.find(successor.second) != current_ASAP.end())
1424  {
1425  current_ASAP.at(successor.second) =
1426  std::max(ControlStep(static_cast<unsigned int>(
1427  floor(ending_time.find(current_vertex)->second / clock_cycle))),
1428  current_ASAP.find(successor.second)->second);
1429  }
1430  else
1431  {
1432  current_ASAP.emplace(successor.second,
1433  ControlStep(static_cast<unsigned int>(
1434  floor(ending_time.find(current_vertex)->second / clock_cycle))));
1435  }
1438  InEdgeIterator ei, ei_end;
1439  for(boost::tie(ei, ei_end) = boost::in_edges(successor.second, *flow_graph); ei != ei_end; ei++)
1440  {
1441  vertex source = boost::source(*ei, *flow_graph);
1442  if(operations.find(source) != operations.end())
1443  {
1444  in_set.insert(source);
1445  }
1446  }
1447  if(in_set.size() == scheduled_predecessors(successor.second))
1448  {
1450  ready_vertices.insert(successor.second);
1451  add_to_priority_queues(priority_queues, ready_resources, successor.second);
1452  }
1453  }
1454  }
1455  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Finished with unit type " + STR(fu_type));
1456  }
1457  if(!restarted_resources.empty())
1458  {
1459  CustomMap<unsigned int, OpVertexSet>::const_iterator bl_end = restarted_resources.end();
1460  for(CustomMap<unsigned int, OpVertexSet>::const_iterator bl_it = restarted_resources.begin();
1461  bl_it != bl_end; ++bl_it)
1462  {
1463  auto v_end = bl_it->second.end();
1464  for(auto v = bl_it->second.begin(); v != v_end; ++v)
1465  {
1466 #if HAVE_UNORDERED
1467  priority_queues[bl_it->first].push(*v);
1468 #else
1469  priority_queues[bl_it->first].insert(*v);
1470 #endif
1471  }
1472  ready_resources.insert(bl_it->first);
1473  }
1474  restarted_resources.clear();
1475  if(prev_scheduled != schedule->num_scheduled())
1476  {
1477  do_again = true;
1479  " Restarted the scheduling loop to accommodate restarted vertices: " +
1480  STR(prev_scheduled) + " vs " + STR(schedule->num_scheduled()));
1481  prev_scheduled = schedule->num_scheduled();
1482  }
1483  }
1484  if(!postponed_resources.empty())
1485  {
1486  CustomMap<unsigned int, OpVertexSet>::const_iterator bl_end = postponed_resources.end();
1487  for(CustomMap<unsigned int, OpVertexSet>::const_iterator bl_it = postponed_resources.begin();
1488  bl_it != bl_end; ++bl_it)
1489  {
1490  auto v_end = bl_it->second.end();
1491  for(auto v = bl_it->second.begin(); v != v_end; ++v)
1492  {
1493 #if HAVE_UNORDERED
1494  priority_queues[bl_it->first].push(*v);
1495 #else
1496  priority_queues[bl_it->first].insert(*v);
1497 #endif
1498  }
1499  ready_resources.insert(bl_it->first);
1500  }
1501  postponed_resources.clear();
1502  if(black_list.empty())
1503  {
1504  do_again = true;
1506  " Restarted the scheduling loop to accommodate postponed vertices");
1507  }
1508  }
1509  } while(do_again);
1510 
1511  CustomMap<unsigned int, OpVertexSet>::const_iterator bl_end = black_list.end();
1512  for(CustomMap<unsigned int, OpVertexSet>::const_iterator bl_it = black_list.begin(); bl_it != bl_end; ++bl_it)
1513  {
1514  auto v_end = bl_it->second.end();
1515  for(auto v = bl_it->second.begin(); v != v_end; ++v)
1516  {
1517 #if HAVE_UNORDERED
1518  priority_queues[bl_it->first].push(*v);
1519 #else
1520  priority_queues[bl_it->first].insert(*v);
1521 #endif
1522  }
1523  }
1525 #if HAVE_UNORDERED
1526  const auto updated =
1527 #endif
1528  Priority->update();
1529 #if HAVE_UNORDERED
1530  if(updated)
1531  {
1532  for(unsigned int i = 0; i < n_resources; i++)
1533  {
1534  priority_queues[i].rehash();
1535  }
1536  }
1537 #endif
1538  cstep_vuses_ARRAYs = cstep_vuses_ARRAYs > 0 ? cstep_vuses_ARRAYs - 1 : 0;
1540  cstep_vuses_others = cstep_vuses_others > 0 ? cstep_vuses_others - 1 : 0;
1542  ++current_cycle;
1543  }
1544 
1545  const auto steps = current_cycle;
1546  schedule->set_csteps(steps);
1547  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, " List Based finished");
1548 }
1549 
1551  const CustomUnorderedSet<vertex>& operations, const vertex v, const unsigned int fu_type, const ControlStep cs,
1552  double& current_starting_time, double& current_ending_time, double& stage_period, bool& cannot_be_chained,
1553  fu_bindingRef res_binding, const ScheduleConstRef schedule, double& phi_extra_time, double setup_hold_time,
1554  CustomMap<std::pair<unsigned int, unsigned int>, double>& local_connection_map)
1555 {
1557  "-->Computing starting and ending time " + GET_NAME(flow_graph, v));
1558  current_starting_time = from_strongtype_cast<double>(cs) * clock_cycle;
1559  bool is_load_store = GET_TYPE(flow_graph, v) & (TYPE_LOAD | TYPE_STORE);
1560  bool is_cond_op = GET_TYPE(flow_graph, v) & (TYPE_IF | TYPE_MULTIIF | TYPE_SWITCH);
1561  bool no_chaining_of_load_and_store = parameters->getOption<bool>(OPT_do_not_chain_memories) &&
1562  (check_LOAD_chaining(operations, v, cs, schedule) || is_load_store);
1563  cannot_be_chained =
1564  is_load_store && check_non_direct_operation_chaining(operations, v, fu_type, cs, schedule, res_binding);
1566  " Initial value of cannot_be_chained=" +
1567  (cannot_be_chained ? std::string("T") : std::string("F")));
1568  InEdgeIterator ei, ei_end;
1569  for(boost::tie(ei, ei_end) = boost::in_edges(v, *flow_graph); ei != ei_end; ei++)
1570  {
1571  vertex from_vertex = boost::source(*ei, *flow_graph);
1572  if(operations.find(from_vertex) == operations.end())
1573  {
1574  continue;
1575  }
1576  if(GET_TYPE(flow_graph, from_vertex) & (TYPE_PHI | TYPE_VPHI))
1577  {
1579  "---Skipping phi predecessor " + GET_NAME(flow_graph, from_vertex));
1580  continue;
1581  }
1583  "-->Considering predecessor " + GET_NAME(flow_graph, from_vertex));
1584  unsigned int from_fu_type = res_binding->get_assign(from_vertex);
1585  const auto cs_prev = schedule->get_cstep(from_vertex).second;
1586  const double fsm_correction = [&]() -> double {
1587  if(is_cond_op)
1588  {
1590  }
1591  if(parameters->getOption<double>(OPT_scheduling_mux_margins) != 0.0)
1592  {
1594  }
1595  if(cs == cs_prev && HLS->allocation_information->is_one_cycle_direct_access_memory_unit(from_fu_type) &&
1597  (!parameters->isOption(OPT_rom_duplication) || !parameters->getOption<bool>(OPT_rom_duplication))) &&
1598  HLSMgr->Rmem->get_maximum_references(HLS->allocation_information->is_memory_unit(from_fu_type) ?
1599  HLS->allocation_information->get_memory_var(from_fu_type) :
1602  {
1604  }
1605  return 0.0;
1606  }();
1607  auto from_statement = flow_graph->CGetOpNodeInfo(from_vertex)->GetNodeId();
1608  auto v_statement = flow_graph->CGetOpNodeInfo(v)->GetNodeId();
1609  const auto v_basic_block_index = flow_graph->CGetOpNodeInfo(v)->bb_index;
1610  auto edge_pair = std::make_pair(from_statement, v_statement);
1611  double connection_time = local_connection_map[edge_pair] =
1612  (schedule->get_cstep_end(from_vertex).second == cs) ?
1613  HLS->allocation_information->GetConnectionTime(from_statement, v_statement,
1614  AbsControlStep(v_basic_block_index, cs)) :
1615  0.0;
1618  double local_ending_time =
1619  connection_time +
1620  ((cs == cs_prev &&
1621  starting_time(from_vertex) < (fsm_correction + (from_strongtype_cast<double>(cs) * clock_cycle))) ?
1622  ending_time.find(from_vertex)->second + fsm_correction +
1623  (from_strongtype_cast<double>(cs) * clock_cycle) - starting_time(from_vertex) :
1624  ending_time.find(from_vertex)->second);
1625  current_starting_time = std::max(current_starting_time, local_ending_time);
1627  "current_starting_time of " + STR(GET_NAME(flow_graph, v)) + " updated to " +
1628  STR(current_starting_time));
1629 
1631  if(schedule->get_cstep_end(from_vertex).second == cs)
1632  {
1633  if(no_chaining_of_load_and_store)
1634  {
1635  cannot_be_chained = true;
1636  }
1637  if(not HLS->allocation_information->CanBeChained(from_vertex, v))
1638  {
1639  cannot_be_chained = true;
1640  }
1641  }
1643  }
1644 
1645  double op_execution_time;
1646  compute_exec_stage_time(fu_type, stage_period, cs, flow_graph, v, op_execution_time, phi_extra_time,
1647  current_starting_time, setup_hold_time);
1648 
1649  current_ending_time = current_starting_time + op_execution_time;
1650 
1652  "<--Operation " + GET_NAME(flow_graph, v) + " starts at " + STR(current_starting_time) +
1653  " and ends at " + STR(current_ending_time) + " execution time " + STR(op_execution_time) +
1654  " stage period " + STR(stage_period) + " phi_extra_time " + STR(phi_extra_time));
1655 }
1656 
1657 void parametric_list_based::compute_exec_stage_time(const unsigned int fu_type, double& stage_period,
1658  const ControlStep cs, const OpGraphConstRef op_graph, vertex v,
1659  double& op_execution_time, double& phi_extra_time,
1660  double current_starting_time, double setup_hold_time)
1661 {
1663  "-->Computing exec stage time of " + GET_NAME(flow_graph_with_feedbacks, v));
1664  const auto bb_index = op_graph->CGetOpNodeInfo(v)->bb_index;
1665  std::pair<double, double> timeLatency = HLS->allocation_information->GetTimeLatency(v, fu_type);
1666  op_execution_time = timeLatency.first;
1667  stage_period = timeLatency.second;
1668 
1670  phi_extra_time = HLS->allocation_information->GetConnectionTime(
1671  flow_graph_with_feedbacks->CGetOpNodeInfo(v)->GetNodeId(), 0, AbsControlStep(bb_index, cs));
1672 
1673  double scheduling_mux_margins =
1674  parameters->getOption<double>(OPT_scheduling_mux_margins) * HLS->allocation_information->mux_time_unit(32);
1675 
1677  unsigned int n_cycles = std::max(1u, HLS->allocation_information->get_cycles(fu_type, v, flow_graph));
1679  op_execution_time + setup_hold_time >= clock_cycle * n_cycles)
1680  {
1681  op_execution_time = clock_cycle * n_cycles - setup_hold_time - phi_extra_time - scheduling_mux_margins - EPSILON;
1682  }
1684  stage_period + setup_hold_time >= clock_cycle)
1685  {
1686  stage_period = clock_cycle - setup_hold_time - phi_extra_time - scheduling_mux_margins - EPSILON;
1687  }
1688 
1690  double initial_execution_time =
1693  fu_type, flow_graph_with_feedbacks->CGetOpNodeInfo(v)->GetOperation(),
1694  static_cast<unsigned>(
1697  .size()));
1698  if(initial_execution_time + setup_hold_time < clock_cycle &&
1699  op_execution_time + setup_hold_time + phi_extra_time + scheduling_mux_margins >= clock_cycle)
1700  {
1701  op_execution_time = clock_cycle - setup_hold_time - phi_extra_time - scheduling_mux_margins - EPSILON;
1702  if(op_execution_time < 0)
1703  {
1704  op_execution_time = clock_cycle - setup_hold_time - scheduling_mux_margins - EPSILON;
1705  phi_extra_time = 0.0;
1706  }
1707  }
1708  if(HLS->allocation_information->get_initiation_time(fu_type, v) > 0 &&
1709  (stage_period + setup_hold_time + phi_extra_time + scheduling_mux_margins >= clock_cycle))
1710  {
1711  stage_period = clock_cycle - setup_hold_time - phi_extra_time - scheduling_mux_margins - EPSILON;
1712  if(stage_period < 0)
1713  {
1714  stage_period = clock_cycle - setup_hold_time - scheduling_mux_margins - EPSILON;
1715  phi_extra_time = 0.0;
1716  }
1717  }
1718  if(stage_period != 0.0)
1719  {
1721  if(n_cycles > 1)
1722  {
1723  op_execution_time = clock_cycle * (n_cycles - 1);
1724  if(stage_period > clock_cycle)
1725  {
1726  op_execution_time += clock_cycle - EPSILON;
1727  }
1728  else
1729  {
1730  op_execution_time += stage_period;
1731  }
1732  op_execution_time -= current_starting_time - from_strongtype_cast<double>(cs) * clock_cycle;
1733  }
1734  else
1735  {
1736  THROW_ERROR("unexpected case");
1737  }
1738  }
1743  {
1744  stage_period = 0.0;
1745  }
1746  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Execution time is " + STR(op_execution_time));
1747 }
1748 
1749 bool parametric_list_based::BB_update_resources_use(unsigned int& used_resources, const unsigned int fu_type) const
1750 {
1751  if(used_resources == HLS->allocation_information->get_number_fu(fu_type))
1752  {
1753  return false;
1754  }
1755  else
1756  {
1757  used_resources++;
1758  return true;
1759  }
1760 }
1761 
1763  std::set<unsigned int, resource_ordering_functor>& ready_resources,
1764  const vertex v) const
1765 {
1766  unsigned int fu_name;
1768  {
1769 #if HAVE_UNORDERED
1770  priority_queue[fu_name].push(v);
1771 #else
1773  "---" + GET_NAME(flow_graph, v) + " bound to " +
1774  HLS->allocation_information->get_fu_name(fu_name).first);
1775  priority_queue[fu_name].insert(v);
1776 #endif
1777  ready_resources.insert(fu_name);
1778  }
1779  else
1780  {
1782  const CustomOrderedSet<unsigned int>::const_iterator fu_set_it_end = fu_set.end();
1783  for(auto fu_set_it = fu_set.begin(); fu_set_it != fu_set_it_end; ++fu_set_it)
1784  {
1785 #if HAVE_UNORDERED
1786  priority_queue[*fu_set_it].push(v);
1787 #else
1788  priority_queue[*fu_set_it].insert(v);
1789 #endif
1790  ready_resources.insert(*fu_set_it);
1791  }
1792  }
1793 }
1794 
1796 {
1797  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "compute function topological order...");
1798  std::list<vertex> topology_sorted_vertex;
1799  const CallGraphManagerConstRef CG = HLSMgr->CGetCallGraphManager();
1800  CG->CGetCallGraph()->TopologicalSort(topology_sorted_vertex);
1801 
1802  CustomOrderedSet<unsigned> reachable_functions = CG->GetReachedFunctionsFrom(funId);
1803 
1804  std::list<unsigned int> topological_sorted_functions;
1805  for(auto v : topology_sorted_vertex)
1806  {
1807  auto fun_id = CG->get_function(v);
1808  if(reachable_functions.find(fun_id) != reachable_functions.end())
1809  {
1810  topological_sorted_functions.push_front(fun_id);
1811  }
1812  }
1813  reachable_proxy_functions.clear();
1814  for(auto v : topological_sorted_functions)
1815  {
1816  auto curr_v_name = HLSMgr->CGetFunctionBehavior(v)->CGetBehavioralHelper()->get_function_name();
1817  if(HLSMgr->Rfuns->has_proxied_shared_functions(v))
1818  {
1819  for(const auto& p : HLSMgr->Rfuns->get_proxied_shared_functions(v))
1820  {
1821  reachable_proxy_functions[curr_v_name].insert(p);
1822  }
1823  }
1824 
1825  for(auto c : CG->get_called_by(v))
1826  {
1827  auto called_name = HLSMgr->CGetFunctionBehavior(c)->CGetBehavioralHelper()->get_function_name();
1828  if(reachable_proxy_functions.find(called_name) != reachable_proxy_functions.end())
1829  {
1830  for(const auto& cp : reachable_proxy_functions.at(called_name))
1831  {
1832  reachable_proxy_functions[curr_v_name].insert(cp);
1833  }
1834  }
1835  }
1836  }
1837 }
1838 
1840 {
1841  long int step_time = 0;
1843  {
1844  START_TIME(step_time);
1845  }
1846  const FunctionBehaviorConstRef FB = HLSMgr->CGetFunctionBehavior(funId);
1847  const BBGraphConstRef bbg = FB->CGetBBGraph();
1848  const OpGraphConstRef op_graph = FB->CGetOpGraph(FunctionBehavior::CFG);
1849  std::deque<vertex> vertices;
1850  boost::topological_sort(*bbg, std::front_inserter(vertices));
1851  auto viend = vertices.end();
1852  auto ctrl_steps = ControlStep(0u);
1853 
1855  {
1857  }
1859  "-->Scheduling Information of function " + FB->CGetBehavioralHelper()->get_function_name() + ":");
1862  for(auto vi = vertices.begin(); vi != viend; ++vi)
1863  {
1864  OpVertexSet operations(op_graph);
1865  std::list<vertex> bb_operations = bbg->CGetBBNodeInfo(*vi)->statements_list;
1866  for(auto& bb_operation : bb_operations)
1867  {
1868  if(HLS->operations.find(bb_operation) != HLS->operations.end())
1869  {
1870  operations.insert(bb_operation);
1871  }
1872  }
1874  "performing scheduling of basic block " + STR(bbg->CGetBBNodeInfo(*vi)->block->number));
1875  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, " .operations: " + STR(operations.size()));
1876 
1877  exec(operations, ctrl_steps);
1878 
1879  ctrl_steps = HLS->Rsch->get_csteps();
1880  if(parameters->getOption<bool>(OPT_print_dot))
1881  {
1882  auto subgraph = FB->CGetOpGraph(FunctionBehavior::FSDG, operations);
1883  HLS->Rsch->WriteDot("HLS_scheduling_BB" + STR(bbg->CGetBBNodeInfo(*vi)->block->number) + ".dot", subgraph,
1884  &operations);
1885  }
1886  }
1887  HLS->Rsch->set_spec(get_spec());
1888 
1890  double min_slack = std::numeric_limits<double>::max();
1891  for(auto operation : ending_time)
1892  {
1893  double realClock = HLS->HLS_C->get_clock_period();
1894 
1895  double endingTime = operation.second;
1896  const auto endControlStep = HLS->Rsch->get_cstep_end(operation.first).second;
1897  double slack = (from_strongtype_cast<double>(endControlStep) + 1) * clock_cycle - endingTime + realClock -
1899  if(slack < 0)
1900  {
1901  slack = EPSILON / 2;
1902  }
1903  if(min_slack > slack)
1904  {
1906  std::string("Operation constraining the maximum frequency:") +
1907  GET_NAME(flow_graph, operation.first) + " slack=" + STR(slack));
1908  }
1909  min_slack = std::min(min_slack, slack);
1910  }
1912  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "---Number of control steps: " + STR(ctrl_steps));
1913 
1915  {
1916  HLS->Rsch->print(HLS->Rfu);
1917  }
1918 
1919  double maxFrequency = 1000.0 / (HLS->HLS_C->get_clock_period() - HLS->allocation_information->getMinimumSlack());
1921  "---Minimum slack: " + STR(HLS->allocation_information->getMinimumSlack()));
1922  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "---Estimated max frequency (MHz): " + STR(maxFrequency));
1923 
1926  {
1927  STOP_TIME(step_time);
1928  }
1930  {
1932  "---Time to perform scheduling: " + print_cpu_time(step_time) + " seconds");
1933  }
1935  {
1937  }
1938 
1939  if(parameters->getOption<bool>(OPT_print_dot))
1940  {
1941  HLS->Rsch->WriteDot("HLS_scheduling.dot");
1942  }
1944  {
1945  const std::string function_name = FB->CGetBehavioralHelper()->get_function_name();
1946  xml_document document;
1947  xml_element* nodeRoot = document.create_root_node("hls");
1948  HLS->xwrite(nodeRoot, FB->CGetOpGraph(FunctionBehavior::FDFG));
1949  document.write_to_file_formatted(GetPath(function_name + "_scheduling.xml"));
1950  }
1952 }
1953 
1955  unsigned int current_vertex_cstep, vertex v)
1956 {
1957  const auto operation = flow_graph->CGetOpNodeInfo(v)->GetOperation();
1958  bool is_load_store = GET_TYPE(flow_graph, v) & (TYPE_LOAD | TYPE_STORE);
1959  if(not is_load_store)
1960  {
1961  return false;
1962  }
1963  std::queue<vertex> fifo;
1964  InEdgeIterator eo, eo_end;
1965  for(boost::tie(eo, eo_end) = boost::in_edges(v, *flow_graph); eo != eo_end; eo++)
1966  {
1967  auto s = boost::source(*eo, *flow_graph);
1968  if(operations.find(s) != operations.end())
1969  {
1970  fifo.push(s);
1971  }
1972  }
1973  while(!fifo.empty())
1974  {
1975  vertex current_op = fifo.front();
1976  fifo.pop();
1977  if(current_vertex_cstep == static_cast<unsigned int>(floor(ending_time.find(current_op)->second / clock_cycle)))
1978  {
1979  if(GET_TYPE(flow_graph, current_op) & (TYPE_LOAD | TYPE_STORE))
1980  {
1981  return true;
1982  }
1983  for(boost::tie(eo, eo_end) = boost::in_edges(current_op, *flow_graph); eo != eo_end; eo++)
1984  {
1985  auto s = boost::source(*eo, *flow_graph);
1986  if(operations.find(s) != operations.end())
1987  {
1988  fifo.push(s);
1989  }
1990  }
1991  }
1992  }
1993  return false;
1994 }
1995 
1997  unsigned int current_vertex_cstep, vertex v)
1998 {
1999  const auto operation = flow_graph->CGetOpNodeInfo(v)->GetOperation();
2000  bool is_load_store = GET_TYPE(flow_graph, v) & (TYPE_LOAD | TYPE_STORE);
2001  if(not is_load_store)
2002  {
2003  return false;
2004  }
2005  std::queue<vertex> fifo;
2006  OutEdgeIterator eo, eo_end;
2007  for(boost::tie(eo, eo_end) = boost::out_edges(v, *flow_graph); eo != eo_end; eo++)
2008  {
2009  auto s = boost::source(*eo, *flow_graph);
2010  if(operations.find(s) != operations.end())
2011  {
2012  fifo.push(s);
2013  }
2014  }
2015  while(!fifo.empty())
2016  {
2017  vertex current_op = fifo.front();
2018  fifo.pop();
2019  if(current_vertex_cstep == static_cast<unsigned int>(floor(starting_time(current_op) / clock_cycle)))
2020  {
2021  if(GET_TYPE(flow_graph, current_op) & (TYPE_LOAD | TYPE_STORE))
2022  {
2023  return true;
2024  }
2025  for(boost::tie(eo, eo_end) = boost::out_edges(current_op, *flow_graph); eo != eo_end; eo++)
2026  {
2027  auto s = boost::source(*eo, *flow_graph);
2028  if(operations.find(s) != operations.end())
2029  {
2030  fifo.push(s);
2031  }
2032  }
2033  }
2034  }
2035  return false;
2036 }
2037 
2038 #define REMOVE_DIRECT_TO_INDIRECT 1
2040  vertex current_v, unsigned int v_fu_type,
2041  const ControlStep cs, const ScheduleConstRef schedule,
2042  fu_bindingRef res_binding) const
2043 {
2044  bool v_is_indirect =
2046  bool v_is_one_cycle_direct_access =
2049  (!HLS->Param->isOption(OPT_rom_duplication) || !parameters->getOption<bool>(OPT_rom_duplication)))) &&
2050  HLSMgr->Rmem->get_maximum_references(HLS->allocation_information->is_memory_unit(v_fu_type) ?
2054 
2056  CustomUnorderedSet<vertex> already_analyzed_operations;
2057 
2059  OpVertexSet to_be_analyzed(flow_graph);
2060  InEdgeIterator ie, ie_end;
2061  for(boost::tie(ie, ie_end) = boost::in_edges(current_v, *flow_graph); ie != ie_end; ie++)
2062  {
2063  auto v = boost::source(*ie, *flow_graph);
2064  if(operations.find(v) != operations.end())
2065  {
2066  to_be_analyzed.insert(v);
2067  }
2068  }
2069  while(!to_be_analyzed.empty())
2070  {
2071  vertex current_op = *(to_be_analyzed.begin());
2072  to_be_analyzed.erase(to_be_analyzed.begin());
2073  already_analyzed_operations.insert(current_op);
2074  if(cs == schedule->get_cstep_end(current_op).second)
2075  {
2076  unsigned int from_fu_type = res_binding->get_assign(current_op);
2077  if((GET_TYPE(flow_graph, current_op) & TYPE_LOAD) and
2078  (v_is_indirect or
2079  (v_is_one_cycle_direct_access and
2082  {
2083  return true;
2084  }
2085  for(boost::tie(ie, ie_end) = boost::in_edges(current_op, *flow_graph); ie != ie_end; ie++)
2086  {
2087  const auto source = boost::source(*ie, *flow_graph);
2088  if(operations.find(source) != operations.end() &&
2089  already_analyzed_operations.find(source) == already_analyzed_operations.end())
2090  {
2091  to_be_analyzed.insert(source);
2092  }
2093  }
2094  }
2095  }
2096  return false;
2097 }
2098 
2100  vertex current_v, const ControlStep cs,
2101  const ScheduleConstRef schedule,
2102  fu_bindingRef res_binding) const
2103 {
2105  std::queue<vertex> fifo;
2106  InEdgeIterator eo, eo_end;
2107  for(boost::tie(eo, eo_end) = boost::in_edges(current_v, *flow_graph); eo != eo_end; eo++)
2108  {
2109  auto v = boost::source(*eo, *flow_graph);
2110  if(operations.find(v) != operations.end())
2111  {
2112  fifo.push(v);
2113  }
2114  }
2115  while(!fifo.empty())
2116  {
2117  vertex current_op = fifo.front();
2118  fifo.pop();
2119  if(cs == schedule->get_cstep_end(current_op).second)
2120  {
2121  unsigned int from_fu_type = res_binding->get_assign(current_op);
2122  if((GET_TYPE(flow_graph, current_op) & TYPE_LOAD) &&
2124  {
2125  return true;
2126  }
2127  for(boost::tie(eo, eo_end) = boost::in_edges(current_op, *flow_graph); eo != eo_end; eo++)
2128  {
2129  auto v = boost::source(*eo, *flow_graph);
2130  if(operations.find(v) != operations.end())
2131  {
2132  fifo.push(v);
2133  }
2134  }
2135  }
2136  }
2137  return false;
2138 }
2139 
2141  const ControlStep cs, const ScheduleConstRef schedule) const
2142 {
2144  std::queue<vertex> fifo;
2145  InEdgeIterator eo, eo_end;
2146  for(boost::tie(eo, eo_end) = boost::in_edges(current_v, *flow_graph); eo != eo_end; eo++)
2147  {
2148  auto v = boost::source(*eo, *flow_graph);
2149  if(operations.find(v) != operations.end())
2150  {
2151  fifo.push(v);
2152  }
2153  }
2154  while(!fifo.empty())
2155  {
2156  vertex current_op = fifo.front();
2157  fifo.pop();
2158  if(cs == schedule->get_cstep_end(current_op).second)
2159  {
2160  if(GET_TYPE(flow_graph, current_op) & TYPE_LOAD)
2161  {
2162  return true;
2163  }
2164  for(boost::tie(eo, eo_end) = boost::in_edges(current_op, *flow_graph); eo != eo_end; eo++)
2165  {
2166  auto v = boost::source(*eo, *flow_graph);
2167  if(operations.find(v) != operations.end())
2168  {
2169  fifo.push(v);
2170  }
2171  }
2172  }
2173  }
2174  return false;
2175 }
2176 
2179 {
2181  Scheduling::ComputeHLSRelationships(relationship_type);
2182  switch(relationship_type)
2183  {
2185  {
2186 #if HAVE_ILP_BUILT
2187  if(parameters->getOption<HLSFlowStep_Type>(OPT_scheduling_algorithm) == HLSFlowStep_Type::SDC_SCHEDULING
2188 #if HAVE_FROM_PRAGMA_BUILT
2189  and HLSMgr->get_HLS(funId) and
2190  HLSMgr->CGetFunctionBehavior(funId)->CGetBehavioralHelper()->GetOmpForDegree() == 0
2191 #endif
2192  )
2193  {
2194  ret.insert(std::make_tuple(HLSFlowStep_Type::SDC_SCHEDULING, HLSFlowStepSpecializationConstRef(),
2196  }
2197 #endif
2200  break;
2201  }
2203  {
2204  break;
2205  }
2207  {
2208  break;
2209  }
2210  default:
2211  THROW_UNREACHABLE("");
2212  }
2213  return ret;
2214 }
#define TYPE_SWITCH
constant identifying the node type of a SWITCH operation.
Definition: op_graph.hpp:105
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...
double get_area(const unsigned int fu_name) const
Returns the area for a given functional unit.
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
const HLS_managerRef HLSMgr
information about all the HLS synthesis
Definition: hls_step.hpp:205
This is a specialization based on mobility.
Definition: priority.hpp:106
bool check_direct_operation_chaining(const CustomUnorderedSet< vertex > &operations, vertex current_v, const ControlStep cs, const ScheduleConstRef schedule, fu_bindingRef res_binding) const
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
ControlStep get_csteps() const
This method returns the number of control steps.
Definition: schedule.hpp:216
vertex2float starting_time
The starting time given the scheduling (used for chaining)
boost::graph_traits< graph >::out_edge_iterator OutEdgeIterator
out_edge_iterator definition.
Definition: graph.hpp:1312
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
#define GET_TYPE(data, vertex_index)
Helper macro returning the type associated with a node.
const ParametricListBased_Metric parametric_list_based_metric
The metric used in list based.
#define PRINT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
void setMinimumSlack(const double slack)
set the minimum slack of the component estimated by scheduling
Functor used to compare which of two resources has to be considered first in the scheduling.
void Initialize() override
Initialize the step (i.e., like a constructor, but executed just before exec.
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
const ParameterConstRef Param
class containing all the parameters
Definition: hls.hpp:169
#define TYPE_MULTIIF
constant identifying the a multi-way if
Definition: op_graph.hpp:202
#define TYPE_VPHI
constant string identifying an operation node of type virtual phi-nodes
Definition: op_graph.hpp:162
#define CTRL_STEP_MULTIPLIER
string target
Definition: lenet_tvm.py:16
#define GET_CLASS(obj)
Macro returning the actual type of an object.
void add_to_priority_queues(PriorityQueues &priority_queue, std::set< unsigned int, resource_ordering_functor > &ready_resources, const vertex v) const
Adds the vertex v to the priority queues.
Dest from_strongtype_cast(Source source)
std::string get_function_name() const
Return the name of the function.
#define TYPE_IF
constant identifying the node type of an IF operation.
Definition: op_graph.hpp:100
const int output_level
The output level.
compare_vertex_by_name(const OpGraphConstRef &G)
Constructor.
RelationshipType
The relationship type.
std::map< std::string, std::set< std::string > > reachable_proxy_functions
reachable proxy from a given function
CustomMap< unsigned int, double > starting_times
The absolute starting time of each operation as computed by the scheduling Key is the index of the gi...
Definition: schedule.hpp:154
Source must be executed to satisfy target.
AbsControlStep get_cstep(const vertex &op) const
Returns the clock cycle where the given operation has been scheduled.
Definition: schedule.cpp:270
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...
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
unsigned int num_scheduled() const
Returns the number of scheduled operations.
Definition: schedule.cpp:324
unsigned int get_assign(const vertex &v) const
Returns the functional unit assigned to the vertex.
Definition: fu_binding.cpp:242
const unsigned int funId
identifier of the function to be processed (0 means that it is a global step)
void set_csteps(ControlStep cs)
This method sets the number of control steps.
Definition: schedule.hpp:225
#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...
CustomOrderedMap< T, U > CustomMap
Definition: custom_map.hpp:167
boost::graph_traits< graph >::in_edge_iterator InEdgeIterator
in_edge_iterator definition.
Definition: graph.hpp:1310
void Initialize() override
Initialize the step (i.e., like a constructor, but executed just before exec.
Definition: scheduling.cpp:73
exceptions managed by PandA
AbsControlStep get_cstep_end(const vertex &op) const
Return the last clock cycle in which the operation execute.
Definition: schedule.cpp:302
double get_DSPs(const unsigned int fu_name) const
return an estimation of the number of DSPs used by the unit
AllocationInformationRef allocation_information
Store the technology information.
Definition: hls.hpp:115
resource_ordering_functor(const AllocationInformationConstRef _all)
Constructor.
Class managing map of the vertexes on a generic object.
Definition: Vertex.hpp:59
Functor to sort vertex by node name.
Definition of hash function for EdgeDescriptor.
Definition: graph.hpp:1321
OpVertexSet operations
Set representing the subset of operations in the specification to be implemented. ...
Definition: hls.hpp:102
void xwrite(xml_element *rootnode, const OpGraphConstRef data)
Writes current HLS results to XML node.
Definition: hls.cpp:188
#define min(x, y)
std::string GetSignature() const override
Return the contribution to the signature of a step given by the specialization.
Sorter for connection.
~parametric_list_based() override
Destructor.
This class contains the base representation for a generic frontend flow step which works on a single ...
absl::flat_hash_map< T, U, Hash, Eq, Alloc > CustomUnorderedMapUnstable
Definition: custom_map.hpp:156
const OpVertexMap< double > & order
copy of the order: control step associated with the vertices.
Data structure describing a basic block at tree level.
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 OUTPUT_LEVEL_MINIMUM
minimum debugging print is performed.
Absolute Control step First field is the basic block Second field is the relative control step...
Definition: schedule.hpp:89
Include a set of utilities used to manage CPU time measures.
#define TYPE_LOAD
Constant string identifying a memory load operation.
Definition: op_graph.hpp:172
PrioritySorter(const refcount< priority_data< int >> priority, const OpGraphConstRef op_graph)
Constructor.
void compute_starting_ending_time_asap(const CustomUnorderedSet< vertex > &operations, const vertex v, const unsigned int fu_type, const ControlStep cs, double &current_starting_time, double &current_ending_time, double &stage_period, bool &cannot_be_chained, fu_bindingRef res_binding, const ScheduleConstRef schedule, double &phi_extra_time, double setup_hold_time, CustomMap< std::pair< unsigned int, unsigned int >, double > &local_connection_map)
Given the control step in which an operation is scheduled, compute the exact starting and ending time...
A set of operation vertices.
Definition: op_graph.hpp:654
bool operator()(const vertex &a, const vertex &b) const
functor function used to compare two vertices with respect to the control step associated with the ve...
#define TYPE_PHI
constant string identifying an operation node of type PHI
Definition: op_graph.hpp:135
static std::string GetMangledFunctionName(const function_decl *fd)
Return the mangled function name.
#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 max
Definition: backprop.h:17
const ParametricListBased_Metric parametric_list_based_metric
The used metric.
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.
const OpNodeInfoConstRef CGetOpNodeInfo(const vertex node) const
Returns the info associated with a node.
Definition: op_graph.hpp:843
Class specifying ALAP and ASAP algorithms.
#define START_TIME(time_var)
Macro used to store the start time into time_var.
Definition: cpu_time.hpp:133
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
System dependence graph with feedback.
fu_bindingRef Rfu
Store the refcounted functional unit binding of the operations.
Definition: hls.hpp:121
std::vector< std::set< vertex, PrioritySorter > > PriorityQueues
ScheduleRef Rsch
Store the refcounted scheduling of the operations.
Definition: hls.hpp:118
void WriteDot(const std::string &file_name, OpGraphConstRef sub_op_graph=OpGraphConstRef(), OpVertexSet *opSet=nullptr) const
Function that writes the dot file of the scheduling by using the AT&T direct graph representation...
Definition: schedule.cpp:214
unsigned int get_proxy_memory_var(const unsigned int fu_name) const
return the var associated with the proxy unit
const OpGraphConstRef & op_graph
#define TYPE_GOTO
A vertex is of type TYPE_GOTO when it is associated with a goto expression.
Definition: op_graph.hpp:157
Functor used to compare two vertices with respect to an order based on the control steps associated w...
This class specifies the characteristic of a particular operation working on a given functional unit...
static bool check_if_is_live_in_next_cycle(const std::set< vertex, cs_ordering_functor > &live_vertices, const ControlStep current_cycle, const OpVertexMap< double > &ending_time, double clock_cycle)
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.
Control flow graph.
HLSFlowStep_Type
Definition: hls_step.hpp:95
const std::map< vertex, unsigned int > & ref
Topological sorted vertices.
Class specification of the data structures used to manage technology information. ...
#define TYPE_EXTERNAL
constant identifying the node type of a EXTERNAL operation (a function call)
Definition: op_graph.hpp:95
static bool has_element_in_common(const std::set< std::string > &set1, const std::set< std::string > &set2)
const OpGraphConstRef op_graph
The operation graph.
void AddConnectionTimes(unsigned int first_operation, unsigned int second_operation, const double value)
Add fan out correction time.
Definition: schedule.cpp:1412
Classes to describe design flow graph.
const OpGraphConstRef & op_graph
void set_execution_end(const vertex &op, ControlStep c_step_end)
Sets the ending clock cycle for the given operation.
Definition: schedule.cpp:246
void write_to_file_formatted(const std::filesystem::path &filename)
Write the document to a file.
void exec(const OpVertexSet &operations, ControlStep current_cycle)
Function that computes the List-Based scheduling of the graph.
void bind(const vertex &v, unsigned int unit, unsigned int index=std::numeric_limits< unsigned int >::max())
Binds an operation vertex to a functional unit.
Definition: fu_binding.cpp:173
#define STOP_TIME(time_var)
Macro used to store the elapsed time into time_var.
Definition: cpu_time.hpp:136
const OpGraphInfoConstRef CGetOpGraphInfo() const
Returns the property associated with the graph.
Definition: op_graph.hpp:871
xml_element * create_root_node(const std::string &_name)
Creates the root node.
bool operator()(const vertex &a, const vertex &b) const
Datastructure to describe functions allocation in high-level synthesis.
#define TYPE_STORE
Constant string identifying a memory store operation.
Definition: op_graph.hpp:177
double mux_time_unit(unsigned long long fu_prec) const
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
utility function used to read files.
OpGraphConstRef flow_graph
The dependence graph.
#define PROXY_PREFIX
double estimate_controller_delay_fb() const
estimate the delay of the controller in feedback mode
#define TYPE_FOR
constant string identifying the node type of an WHILE operation.
Definition: op_graph.hpp:115
#define TYPE_RW
Constant identifying if a TYPE_EXTERNAL write or read memory.
Definition: op_graph.hpp:217
General class used to describe a graph in PandA.
Definition: graph.hpp:771
const BehavioralHelperConstRef CGetBehavioralHelper() const
Returns the helper associated with the function.
boost::graph_traits< graph >::vertex_iterator VertexIterator
vertex_iterator definition.
Definition: graph.hpp:1307
Classes specification of the tree_node data structures.
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
This package is used by all HLS packages to manage resource constraints and characteristics.
This file collects some utility functions and macros.
bool operator()(const vertex x, const vertex y) const
Compare position of two vertices.
Class managing ALAP and ASAP algorithms.
Definition: ASLAP.hpp:75
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
Wrapper of design_flow.
Data structure definition for HLS constraints.
bool operator()(const unsigned int &a, const unsigned int &b) const
functor function used to compare two resources with respect to their performances ...
Functor used to compare two vertices with respect to a priority object.
Definition: priority.hpp:170
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.
This is a specialization based on mobility.
Definition: priority.hpp:126
This is a specialization based on a given fixed priority value.
Definition: priority.hpp:150
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...
Information about specialization of parametric list based step.
bool store_in_chaining_with_load_out(const CustomUnorderedSet< vertex > &operations, unsigned int current_vertex_cstep, vertex v)
void print(fu_bindingRef Rfu=fu_bindingRef()) const
Function that prints the class schedule.
Definition: schedule.cpp:126
std::string print_cpu_time(long int t)
massage a long which represents a time interval in milliseconds, into a string suitable for output ...
Definition: cpu_time.hpp:110
const CustomUnorderedSet< std::tuple< HLSFlowStep_Type, HLSFlowStepSpecializationConstRef, HLSFlowStep_Relationship > > ComputeHLSRelationships(const DesignFlowStep::RelationshipType relationship_type) const override
Compute the relationship of this step.
Class definition of the list_based structure.
cs_ordering_functor(const OpVertexMap< double > &o, const OpGraphConstRef &opGraph)
Constructor.
void set_spec(const CustomUnorderedMap< vertex, bool > &spec_map)
Sets the speculation map.
Definition: schedule.hpp:245
DesignFlowStep_Status InternalExec() override
Execute the step.
This class describes all classes used to represent a structural object.
#define OUTPUT_LEVEL_PEDANTIC
verbose debugging print is performed.
std::string GetPath(std::filesystem::path path)
Definition: fileIO.hpp:140
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...
Speculation graph.
Data flow graph with feedback.
ParametricListBased_Metric
bool is_scheduled(const vertex &op) const
Returns true if the given operation has been already scheduled, false otherwise.
Definition: schedule.cpp:259
parametric_list_based(const ParameterConstRef parameters, const HLS_managerRef HLSMgr, unsigned int _funId, const DesignFlowManagerConstRef design_flow_manager, const HLSFlowStepSpecializationConstRef hls_flow_step_specialization)
This is the constructor of the list_based.
edge_integer_order_by_map(const std::map< vertex, unsigned int > &_ref, const graph *)
Graph.
unsigned int get_number_channels(unsigned int fu_name) const
return the number of channels available for the functional unit
#define OUTPUT_LEVEL_VERY_PEDANTIC
verbose debugging print is performed.
bool CanBeChained(const unsigned int first_statement_index, const unsigned int second_statement_index) const
Check if two statements can be chained.
T * GetPointer(const refcount< U > &t)
Template function used to hide dynamic_cast The template parameter T represents a type of an object h...
Definition: refcount.hpp:237
Data structure used to store the functional-unit binding of the vertexes.
const OpGraphConstRef CGetOpGraph(FunctionBehavior::graph_type gt) const
This method returns the operation graphs.
OpVertexMap< double > ending_time
The ending time given the scheduling (used for chaining)
Class specification of the basic_block structure.
unsigned int get_memory_var(const unsigned int fu_name) const
Returns the base address of the functional unit.
hlsRef HLS
HLS data structure of the function to be analyzed.
bool BB_update_resources_use(unsigned int &used_resources, const unsigned int fu_type) const
Update the resource map.
CustomMap< unsigned int, double > ending_times
The absolute ending time of each operation as computed by the scheduling Key is the index of the gimp...
Definition: schedule.hpp:158
const BBNodeInfoConstRef CGetBBNodeInfo(const vertex node) const
Return the info associated with a basic block.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
const BBGraphConstRef CGetBBGraph(FunctionBehavior::bb_graph_type gt=FunctionBehavior::BB) const
This method returns the basic block graphs.
#define TYPE_WHILE
constant string identifying the node type of an WHILE operation.
Definition: op_graph.hpp:110
unsigned int get_number_fu(unsigned int fu_name) const
Returns the number of functional unit given its id.
System dependence + anti-dependence + output dependence graph + flow graph.
const AllocationInformationConstRef all
copy of the order: control step associated with the vertices.
bool store_in_chaining_with_load_in(const CustomUnorderedSet< vertex > &operations, unsigned int current_vertex_cstep, vertex v)
store_in_chaining_with_load checks if a store is chained with a load operation or vice versa ...
bool check_non_direct_operation_chaining(const CustomUnorderedSet< vertex > &operations, vertex current_v, unsigned int v_fu_type, const ControlStep cs, const ScheduleConstRef schedule, fu_bindingRef res_binding) const
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 clock_cycle
The clock cycle.
#define REMOVE_DIRECT_TO_INDIRECT
Wrapper to call graph.
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 ...
Generic class managing scheduling algorithms.
Definition: scheduling.hpp:64
x
Return the smallest n such that 2^n >= _x.
const HLS_constraintsRef HLS_C
store the HLS constraints
Definition: hls.hpp:110
int debug_level
The debug level.
This package is used by all HLS packages to manage resource constraints and characteristics.
refcount< const HLSFlowStepSpecialization > HLSFlowStepSpecializationConstRef
const refcount definition of the class
Definition: hls_step.hpp:93
#define TYPE_RET
constant string identifying an operation node of type return expr
Definition: op_graph.hpp:140
virtual const CustomUnorderedSet< std::tuple< HLSFlowStep_Type, HLSFlowStepSpecializationConstRef, HLSFlowStep_Relationship > > ComputeHLSRelationships(const DesignFlowStep::RelationshipType relationship_type) const override
Compute the relationship of this step.
Definition: scheduling.cpp:96
#define DEBUG_LEVEL_VERBOSE
verbose debugging print is performed.
void CheckSchedulabilityConditions(const CustomUnorderedSet< vertex > &operations, const vertex &current_vertex, ControlStep current_cycle, double &current_starting_time, double &current_ending_time, double &current_stage_period, CustomMap< std::pair< unsigned int, unsigned int >, double > &local_connection_map, double current_cycle_starting_time, double current_cycle_ending_time, double setup_hold_time, double &phi_extra_time, double scheduling_mux_margins, bool unbounded, bool unbounded_Functions, bool LoadStoreOp, const std::set< std::string > &proxy_functions_used, bool cstep_has_RET_conflict, unsigned int fu_type, const vertex2obj< ControlStep > &current_ASAP, const fu_bindingRef res_binding, const ScheduleRef schedule, bool &predecessorsCond, bool &pipeliningCond, bool &cannotBeChained0, bool &chainingRetCond, bool &cannotBeChained1, bool &asyncCond, bool &cannotBeChained2, bool &cannotBeChained3, bool &MultiCond0, bool &MultiCond1, bool &LoadStoreFunctionConflict, bool &FunctionStoreconflict, bool &proxyFunCond, bool unbounded_RW, bool seeMulticycle)
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.
const CustomUnorderedMap< vertex, bool > & get_spec() const
It returns speculation property map.
Definition: scheduling.hpp:115
System dependence + anti-dependence + output dependence graph + flow graph with feedback.
bool is_readonly_memory_unit(const unsigned int fu_name) const
return true in case the functional unit is a read-only memory unit
The key comparison function for edge-integer set based on levels.
void set_execution(const vertex &op, ControlStep c_step)
Sets the starting clock cycle for the given operation.
Definition: schedule.cpp:232
Datastructure to represent memory information in high-level synthesis.
bool check_LOAD_chaining(const CustomUnorderedSet< vertex > &operations, vertex current_v, const ControlStep cs, const ScheduleConstRef schedule) const
OpGraphConstRef flow_graph_with_feedbacks
The dependence graph with feedbacks.
Class specification of the manager of the tree structures extracted from the raw file.
void compute_exec_stage_time(const unsigned int fu_type, double &stage_period, const ControlStep cs, const OpGraphConstRef op_graph, vertex v, double &op_execution_time, double &phi_extra_time, double current_starting_time, double setup_hold_time)
ParametricListBasedSpecialization(const ParametricListBased_Metric parametric_list_based_metric)
Constructor.
A brief description of the C++ Header File.
refcount< ASLAP > ASLAPRef
Definition: ASLAP.hpp:308
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.
const bool speculation
flag to check speculation
Definition: scheduling.hpp:84
unsigned int get_number_fu_types() const
Returns the number of functional units types.
void compute_function_topological_order()
compute_function_topological_order compute reachable function topological order
bool operator()(const std::pair< std::pair< vertex, vertex >, unsigned int > &x, const std::pair< std::pair< vertex, vertex >, unsigned int > &y) const
Compare position of two vertices in topological sorted.
unsigned int GetFuType(const unsigned int operation) const
Return the functional unit type used to execute an operation.
std::string GetKindText() const override
Return the string representation of this.
boost::graph_traits< graph >::edge_descriptor EdgeDescriptor
edge definition.
Definition: graph.hpp:1316
#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