PandA-2024.02
BB_based_stg.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  */
45 #include "BB_based_stg.hpp"
46 
47 #include "Discrepancy.hpp"
48 #include "Parameter.hpp"
51 #include "basic_block.hpp"
52 #include "behavioral_helper.hpp"
53 #include "call_graph.hpp"
54 #include "call_graph_manager.hpp"
55 #include "cpu_time.hpp"
56 #include "custom_map.hpp"
57 #include "custom_set.hpp"
58 #include "dbgPrintHelper.hpp"
59 #include "fu_binding.hpp"
60 #include "function_behavior.hpp"
61 #include "functions.hpp"
62 #include "hls.hpp"
63 #include "hls_constraints.hpp"
64 #include "loop.hpp"
65 #include "loops.hpp"
66 #include "memory.hpp"
67 #include "omp_functions.hpp"
68 #include "op_graph.hpp"
69 #include "schedule.hpp"
72 #include "string_manipulation.hpp" // for GET_CLASS
73 #include "structural_manager.hpp"
74 #include "technology_manager.hpp"
75 #include "technology_node.hpp"
76 #include "time_info.hpp"
77 #include "tree_basic_block.hpp"
78 #include "tree_helper.hpp"
79 #include "tree_manager.hpp"
80 #include <boost/foreach.hpp>
81 #include <boost/graph/depth_first_search.hpp>
82 #include <boost/graph/graph_traits.hpp>
83 #include <boost/graph/incremental_components.hpp>
84 #include <cmath>
85 
86 class OpVertexSchedSorter : std::binary_function<vertex, vertex, bool>
87 {
88  private:
91 
92  public:
97  explicit OpVertexSchedSorter(const ScheduleConstRef _sch) : sch(_sch)
98  {
99  }
100 
107  bool operator()(const vertex x, const vertex y) const
108  {
109  return sch->get_cstep(x) < sch->get_cstep(y);
110  }
111 };
112 
113 BB_based_stg::BB_based_stg(const ParameterConstRef _parameters, const HLS_managerRef _HLSMgr, unsigned _funId,
114  const DesignFlowManagerConstRef _design_flow_manager)
115  : STG_creator(_parameters, _HLSMgr, _funId, _design_flow_manager, HLSFlowStep_Type::BB_STG_CREATOR)
116 {
117  debug_level = _parameters->get_class_debug_level(GET_CLASS(*this));
118 }
119 
122 {
124  switch(relationship_type)
125  {
127  {
128 #if HAVE_ILP_BUILT
129  if(parameters->getOption<HLSFlowStep_Type>(OPT_scheduling_algorithm) == HLSFlowStep_Type::SDC_SCHEDULING)
130  {
133  }
134  else
135 #endif
136  {
137  ret.insert(std::make_tuple(parameters->getOption<HLSFlowStep_Type>(OPT_scheduling_algorithm),
139  }
140  break;
141  }
143  {
144  break;
145  }
147  {
148  break;
149  }
150  default:
151  THROW_UNREACHABLE("");
152  }
153  return ret;
154 }
155 
157 {
160 }
161 
163 {
164  long int step_time = 0;
166  {
167  START_TIME(step_time);
168  }
169  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Starting creation of STG...");
170 
171  const auto STG_builder = HLS->STG->STG_builder;
172  THROW_ASSERT(STG_builder, "STG constructor not properly initialized");
173 
178 
179  const auto dfgRef = HLSMgr->CGetFunctionBehavior(funId)->CGetOpGraph(FunctionBehavior::DFG);
180 
181  const auto sch = HLS->Rsch;
182 
183  const auto fbb = HLSMgr->CGetFunctionBehavior(funId)->CGetBBGraph(FunctionBehavior::FBB);
184 
186  const auto bb_entry = fbb->CGetBBGraphInfo()->entry_vertex;
187  const auto bb_exit = fbb->CGetBBGraphInfo()->exit_vertex;
188 
189  bool first_state_p;
190  bool have_previous;
191  vertex previous;
192  std::map<vertex, std::list<vertex>> call_states;
193  std::map<vertex, std::list<vertex>> call_operations;
194  CustomOrderedSet<vertex> already_analyzed;
195  VertexIterator vit, vend;
196 
197  const auto is_pipelined = HLSMgr->CGetFunctionBehavior(funId)->is_simple_pipeline();
198 
200  std::map<vertex, std::list<vertex>> global_executing_ops, global_starting_ops, global_ending_ops, global_onfly_ops;
201 
202  const auto CGM = HLSMgr->CGetCallGraphManager();
203  const auto top_functions = CGM->GetRootFunctions();
204  const auto needMemoryMappedRegisters = top_functions.count(funId) ?
205  parameters->getOption<bool>(OPT_memory_mapped_top) :
206  HLSMgr->hasToBeInterfaced(funId);
207  auto has_registered_inputs = HLS->registered_inputs && !needMemoryMappedRegisters;
208  if(top_functions.count(funId) && parameters->getOption<std::string>(OPT_registered_inputs) == "top")
209  {
210  has_registered_inputs = true;
211  }
212  if(HLSMgr->Rfuns->is_a_proxied_function(functions::GetFUName(funId, HLSMgr)) && !needMemoryMappedRegisters)
213  {
214  if(parameters->getOption<std::string>(OPT_registered_inputs) != "no")
215  {
216  has_registered_inputs = true;
217  }
218  }
219  else if(parameters->getOption<std::string>(OPT_registered_inputs) == "yes" && !needMemoryMappedRegisters)
220  {
221  has_registered_inputs = true;
222  }
223  if(parameters->getOption<std::string>(OPT_registered_inputs) != "no" && !has_registered_inputs &&
224  !needMemoryMappedRegisters)
225  {
228  const auto sort_list = CGM->GetReachedBodyFunctions();
229  CustomUnorderedSet<vertex> vertex_subset;
230  for(auto cvertex : sort_list)
231  {
232  vertex_subset.insert(CGM->GetVertex(cvertex));
233  }
234  const auto subgraph = CGM->CGetCallSubGraph(vertex_subset);
235  InEdgeIterator ie_it, ie_it_end;
236  const auto current_vertex = CGM->GetVertex(funId);
237  size_t n_call_sites = 0;
238  for(boost::tie(ie_it, ie_it_end) = boost::in_edges(current_vertex, *subgraph); ie_it != ie_it_end; ++ie_it)
239  {
240  const auto* info = Cget_edge_info<FunctionEdgeInfo, const CallGraph>(*ie_it, *subgraph);
241  n_call_sites += static_cast<size_t>(info->direct_call_points.size()) +
242  static_cast<size_t>(info->indirect_call_points.size());
243  }
244  HLS->call_sites_number = n_call_sites;
245  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "---Number of function call sites = " + STR(n_call_sites));
246  unsigned int n_levels = 0;
247  const auto controller_delay = HLS->allocation_information->EstimateControllerDelay();
248  for(; n_call_sites > (1u << n_levels); ++n_levels)
249  {
250  ;
251  }
252  double mux_time_estimation =
253  (n_levels * HLS->allocation_information->mux_time_unit(32)) + (n_levels > 0 ? controller_delay : 0);
254  if(mux_time_estimation > HLS->allocation_information->getMinimumSlack() && !is_pipelined)
255  {
256  has_registered_inputs = true;
257  }
258  }
259  auto omp_functions = GetPointer<OmpFunctions>(HLSMgr->Rfuns);
260  if(HLS->Param->isOption(OPT_context_switch))
261  {
262  if(omp_functions->kernel_functions.count(funId))
263  {
264  has_registered_inputs = true;
265  }
266  }
267  HLS->registered_inputs = has_registered_inputs;
268 
270  for(boost::tie(vit, vend) = boost::vertices(*fbb); vit != vend; ++vit)
271  {
272  if(*vit == bb_entry)
273  {
274  last_state[*vit] = first_state[*vit] = HLS->STG->get_entry_state();
275  continue;
276  }
277  else if(*vit == bb_exit)
278  {
279  last_state[*vit] = first_state[*vit] = HLS->STG->get_exit_state();
280  continue;
281  }
283  "-->Building STG of BB" + STR(fbb->CGetBBNodeInfo(*vit)->block->number));
284  const auto operations = fbb->CGetBBNodeInfo(*vit);
285  OpVertexSchedSorter schSorter(sch);
286  std::multiset<vertex, OpVertexSchedSorter> ordered_operations(schSorter);
287  for(auto ops : operations->statements_list)
288  {
289  ordered_operations.insert(ops);
290  }
291  if(boost::in_degree(*vit, *fbb) == 1)
292  {
294  InEdgeIterator ie, iend;
295  boost::tie(ie, iend) = boost::in_edges(*vit, *fbb);
296  const auto bb_src = boost::source(*ie, *fbb);
297  if(bb_src == bb_entry)
298  {
299  for(auto stmt : ordered_operations)
300  {
301  if(has_registered_inputs || (GET_TYPE(dfgRef, stmt) & TYPE_PHI))
302  {
304  const auto entry_operations = fbb->CGetBBNodeInfo(bb_src);
306  BB_ids.insert(entry_operations->get_bb_index());
307  const auto s_cur =
308  STG_builder->create_state(entry_operations->statements_list, entry_operations->statements_list,
309  entry_operations->statements_list, BB_ids);
310  STG_builder->connect_state(last_state[bb_src], s_cur,
311  TransitionInfo::StateTransitionType::ST_EDGE_NORMAL);
312  last_state[bb_src] = s_cur;
313  break;
314  }
315  }
316  }
317  }
318 
319  first_state_p = true;
320  have_previous = false;
321  std::map<ControlStep, std::list<vertex>> executing_ops, starting_ops, ending_ops, onfly_ops;
322  auto max_cstep = ControlStep(0u);
323  auto min_cstep = ControlStep(std::numeric_limits<unsigned int>::max());
324 
325  for(auto op : ordered_operations)
326  {
327  if(GET_TYPE(dfgRef, op) & (TYPE_GOTO))
328  {
329  continue;
330  }
331  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Analyzing operation " + GET_NAME(dfgRef, op));
332  if(GET_TYPE(dfgRef, op) & (TYPE_VPHI))
333  {
335  bool can_be_removed = true;
336  OutEdgeIterator oe, oend;
337  for(boost::tie(oe, oend) = boost::out_edges(*vit, *fbb); oe != oend && can_be_removed; ++oe)
338  {
339  const auto tgt = boost::target(*oe, *fbb);
340  if(tgt == *vit)
341  {
342  continue;
343  }
344  const auto out_bb_operations = fbb->CGetBBNodeInfo(tgt);
345  auto obo_it_end = out_bb_operations->statements_list.end();
346  for(auto obo_it = out_bb_operations->statements_list.begin(); obo_it_end != obo_it && can_be_removed;
347  ++obo_it)
348  {
349  if((GET_TYPE(dfgRef, *obo_it) & TYPE_PHI) != 0)
350  {
351  for(const auto& def_edge :
352  GetPointer<const gimple_phi>(HLSMgr->get_tree_manager()->get_tree_node_const(
353  dfgRef->CGetOpNodeInfo(*obo_it)->GetNodeId()))
354  ->CGetDefEdgesList())
355  {
356  if(!def_edge.first)
357  {
358  continue;
359  }
360  if(def_edge.second == operations->get_bb_index())
361  {
362  can_be_removed = false;
363  }
364  }
365  }
366  }
367  }
368  if(can_be_removed)
369  {
370  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Removed operation " + GET_NAME(dfgRef, op));
371  continue;
372  }
373  }
374  if(already_analyzed.find(op) != already_analyzed.end())
375  {
377  "<--Already Analyzed operation " + GET_NAME(dfgRef, op));
378  continue;
379  }
380  const auto cstep = sch->get_cstep(op).second;
381  unsigned int fu_name = HLS->Rfu->get_assign(op);
382  THROW_ASSERT(sch->get_cstep_end(op) >= sch->get_cstep(op), "unexpected condition");
383  const auto delay = sch->get_cstep_end(op).second - sch->get_cstep(op).second;
384  const auto end_step = cstep + delay;
385  max_cstep = std::max(max_cstep, end_step);
386  min_cstep = std::min(min_cstep, cstep);
387  executing_ops[cstep].push_back(op);
388  starting_ops[cstep].push_back(op);
389  const auto initiation_time = HLS->allocation_information->get_initiation_time(fu_name, op);
390  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---initiation_time " + STR(initiation_time));
391  if(initiation_time == 0 || initiation_time > delay)
392  {
393  for(auto c = cstep + 1u; c <= end_step; c++)
394  {
395  executing_ops[c].push_back(op);
396  }
397  }
398  for(auto c = cstep + 1u; c <= end_step; c++)
399  {
400  onfly_ops[c].push_back(op);
401  }
402  ending_ops[end_step].push_back(op);
403  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Analyzed operation " + GET_NAME(dfgRef, op));
404  }
405  vertex s_cur;
406  for(auto l = min_cstep; l <= max_cstep; l++)
407  {
408  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Considering control step " + STR(l));
409  std::list<vertex> exec_ops, start_ops, end_ops, onf_ops;
410  if(executing_ops.find(l) != executing_ops.end())
411  {
412  exec_ops = executing_ops[l];
413  }
414  if(starting_ops.find(l) != starting_ops.end())
415  {
416  start_ops = starting_ops[l];
417  }
418  if(ending_ops.find(l) != ending_ops.end())
419  {
420  end_ops = ending_ops[l];
421  }
422  if(onfly_ops.find(l) != onfly_ops.end())
423  {
424  onf_ops = onfly_ops[l];
425  }
427  BB_ids.insert(operations->get_bb_index());
428  s_cur = STG_builder->create_state(exec_ops, start_ops, end_ops, BB_ids);
429 
430  global_executing_ops[s_cur] = exec_ops;
431  global_starting_ops[s_cur] = start_ops;
432  global_ending_ops[s_cur] = end_ops;
433  global_onfly_ops.insert({s_cur, onf_ops});
434 
435  for(auto exec_op : exec_ops)
436  {
437  const auto tn = HLS->allocation_information->get_fu(HLS->Rfu->get_assign(exec_op));
438  const auto op_tn = GetPointer<functional_unit>(tn)->get_operation(
439  tree_helper::NormalizeTypename(dfgRef->CGetOpNodeInfo(exec_op)->GetOperation()));
440  THROW_ASSERT(GetPointer<operation>(op_tn)->time_m,
441  "Time model not available for operation: " + GET_NAME(dfgRef, exec_op));
442  if(!GetPointer<operation>(op_tn)->is_bounded())
443  {
445  "---" + GET_NAME(dfgRef, exec_op) + " is unbounded");
446  call_operations[s_cur].push_back(exec_op);
447  }
448  }
449  // THROW_ASSERT(call_operations.find(s_cur) == call_operations.end() ||
450  // call_operations.find(s_cur)->second.size() <= 1, "currently only one unbounded operation per state is
451  // admitted");
452  if(call_operations.find(s_cur) != call_operations.end() && call_operations.find(s_cur)->second.size())
453  {
454  THROW_ASSERT(call_operations.find(s_cur) != call_operations.end() &&
455  call_operations.find(s_cur)->second.begin() != call_operations.find(s_cur)->second.end(),
456  "unexpected condition");
457  const auto& call_ops = call_operations.at(s_cur);
458  CustomOrderedSet<unsigned int> call_BB_ids;
459  call_BB_ids.insert(operations->get_bb_index());
460  vertex s_call = STG_builder->create_state(call_ops, std::list<vertex>(), call_ops, call_BB_ids);
461  HLS->STG->GetStg()->GetStateInfo(s_call)->is_dummy = true;
462  call_states[s_cur].push_back(s_call);
464  ops.insert(call_ops.begin(), call_ops.end());
465  if(ops.size() > 1)
466  {
467  HLS->STG->add_multi_unbounded_obj(s_cur, ops);
468  }
469  }
470 
471  if(have_previous)
472  {
473  if(call_states.find(previous) == call_states.end())
474  {
475  STG_builder->connect_state(previous, s_cur, TransitionInfo::StateTransitionType::ST_EDGE_NORMAL);
476  }
477  else
478  {
479  THROW_ASSERT(call_operations.find(previous) != call_operations.end() &&
480  call_operations.find(previous)->second.begin() !=
481  call_operations.find(previous)->second.end(),
482  "unexpected condition");
483  THROW_ASSERT(call_states.count(previous), "unexpected condition");
485  ops.insert(call_operations.at(previous).begin(), call_operations.at(previous).end());
486  for(auto& call_set : call_states.at(previous))
487  {
488  EdgeDescriptor s_e =
489  STG_builder->connect_state(call_set, s_cur, TransitionInfo::StateTransitionType::ST_EDGE_NORMAL);
490  STG_builder->set_unbounded_condition(s_e, ALL_FINISHED, ops, previous);
491  }
492  EdgeDescriptor s_e =
493  STG_builder->connect_state(previous, s_cur, TransitionInfo::StateTransitionType::ST_EDGE_NORMAL);
494  STG_builder->set_unbounded_condition(s_e, ALL_FINISHED, ops, previous);
495  }
496  }
497  else
498  {
499  have_previous = true;
500  }
501  previous = s_cur;
502  if(first_state_p)
503  {
504  first_state[*vit] = s_cur;
505  first_state_p = false;
506  }
507  if(call_states.count(s_cur))
508  {
509  THROW_ASSERT(call_operations.find(s_cur) != call_operations.end() &&
510  call_operations.find(s_cur)->second.begin() != call_operations.find(s_cur)->second.end(),
511  "unexpected condition");
512  THROW_ASSERT(call_states.find(s_cur) != call_states.end() &&
513  call_states.find(s_cur)->second.begin() != call_states.find(s_cur)->second.end(),
514  "unexpected condition");
515  const auto waiting_state = call_states.at(s_cur).front();
516  EdgeDescriptor s_e =
517  STG_builder->connect_state(s_cur, waiting_state, TransitionInfo::StateTransitionType::ST_EDGE_NORMAL);
518 
520  ops.insert(call_operations.at(s_cur).begin(), call_operations.at(s_cur).end());
521  STG_builder->set_unbounded_condition(s_e, NOT_ALL_FINISHED, ops, s_cur);
522 
523  s_e = STG_builder->connect_state(waiting_state, waiting_state,
524  TransitionInfo::StateTransitionType::ST_EDGE_FEEDBACK);
525  STG_builder->set_unbounded_condition(s_e, NOT_ALL_FINISHED, ops, s_cur);
526  }
527  last_state[*vit] = s_cur;
528  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Considered control step " + STR(l));
529  }
531  "<--Built STG of BB" + STR(fbb->CGetBBNodeInfo(*vit)->block->number));
532  }
533 
536  BOOST_FOREACH(EdgeDescriptor e, boost::edges(*fbb))
537  {
538  const auto bb_src = boost::source(e, *fbb);
539  if(last_state.find(bb_src) == last_state.end())
540  {
541  continue;
542  }
543  auto bb_tgt = boost::target(e, *fbb);
545  if(bb_src == bb_entry && bb_tgt == bb_exit)
546  {
547  continue;
548  }
550  "-->Analyzing BB" + STR(fbb->CGetBBNodeInfo(bb_src)->block->number) + "-->" +
551  STR(fbb->CGetBBNodeInfo(bb_tgt)->block->number));
552  vertex s_src, s_tgt;
553  if(bb_src == bb_exit)
554  {
555  s_src = HLS->STG->get_exit_state();
556  }
557  else
558  {
559  THROW_ASSERT(last_state.count(bb_src), "missing a state vertex");
560  s_src = last_state.at(bb_src);
561  }
562  if(bb_tgt == bb_entry)
563  {
564  s_tgt = HLS->STG->get_entry_state();
565  }
566  else if(bb_tgt == bb_exit)
567  {
568  s_tgt = HLS->STG->get_exit_state();
569  }
570  else
571  {
572  while(first_state.find(bb_tgt) == first_state.end())
573  {
574  THROW_ASSERT(boost::out_degree(bb_tgt, *fbb) == 1, "unexpected pattern");
575  OutEdgeIterator oe, oend;
576  boost::tie(oe, oend) = boost::out_edges(bb_tgt, *fbb);
577  bb_tgt = boost::target(*oe, *fbb);
578  }
579  s_tgt = first_state.at(bb_tgt);
580  }
581  // THROW_ASSERT(s_src != s_tgt, "chaining between basic block is not expected");
582 
583  EdgeDescriptor s_e;
584  if(FB_CFG_SELECTOR & fbb->GetSelector(e))
585  {
586  s_e = STG_builder->connect_state(s_src, s_tgt, TransitionInfo::StateTransitionType::ST_EDGE_FEEDBACK);
587  if(call_states.count(s_src))
588  {
589  const auto& call_sets = call_states.at(s_src);
591  ops.insert(call_operations[s_src].begin(), call_operations[s_src].end());
592  if(call_sets.begin() != call_sets.end())
593  {
594  STG_builder->set_unbounded_condition(s_e, ALL_FINISHED, ops, s_src);
595  }
596  for(auto call_set : call_sets)
597  {
598  EdgeDescriptor s_e1 =
599  STG_builder->connect_state(call_set, s_tgt, TransitionInfo::StateTransitionType::ST_EDGE_FEEDBACK);
600  STG_builder->set_unbounded_condition(s_e1, ALL_FINISHED, ops, s_src);
601  }
602  }
603  }
604  else
605  {
606  if(call_states.find(s_src) == call_states.end())
607  {
608  s_e = STG_builder->connect_state(s_src, s_tgt, TransitionInfo::StateTransitionType::ST_EDGE_NORMAL);
609  }
610  else
611  {
612  THROW_ASSERT(call_operations.find(s_src) != call_operations.end() &&
613  call_operations.find(s_src)->second.size() != 0,
614  "State " + HLS->STG->get_state_name(s_src) + " does not contain any call expression");
615  const auto& call_sets = call_states.at(s_src);
617  ops.insert(call_operations.at(s_src).begin(), call_operations.at(s_src).end());
618  for(auto& call_set : call_sets)
619  {
620  EdgeDescriptor s_edge =
621  STG_builder->connect_state(call_set, s_tgt, TransitionInfo::StateTransitionType::ST_EDGE_NORMAL);
622  STG_builder->set_unbounded_condition(s_edge, ALL_FINISHED, ops, s_src);
623  }
624 
625  s_e = STG_builder->connect_state(s_src, s_tgt, TransitionInfo::StateTransitionType::ST_EDGE_NORMAL);
626  STG_builder->set_unbounded_condition(s_e, ALL_FINISHED, ops, s_src);
627  }
628  }
631  const auto bb_node_info = fbb->CGetBBNodeInfo(bb_src);
632  THROW_ASSERT(bb_node_info->statements_list.size(), "at least one operation should belong to this basic block");
633  const auto last_operation = *(bb_node_info->statements_list.rbegin());
634  const CustomOrderedSet<unsigned int>& cfg_edge_ids = fbb->CGetBBEdgeInfo(e)->get_labels(CFG_SELECTOR);
635 
636  if(cfg_edge_ids.size())
637  {
638  auto edgeType = *cfg_edge_ids.begin();
640  if(edgeType == T_COND || edgeType == F_COND)
641  {
642  if(edgeType == T_COND)
643  {
644  t = TRUE_COND;
645  }
646  else if(edgeType == F_COND)
647  {
648  t = FALSE_COND;
649  }
650  STG_builder->set_condition(s_e, t, last_operation);
651  }
652  else
653  {
655  bool has_default = false;
656  for(auto label : cfg_edge_ids)
657  {
658  if(label == default_COND)
659  {
660  has_default = true;
661  }
662  else
663  {
664  labels.insert(label);
665  }
666  }
667  STG_builder->set_switch_condition(s_e, last_operation, labels, has_default);
668  }
669  }
671  "<--Analyzed BB" + STR(fbb->CGetBBNodeInfo(bb_src)->block->number) + "-->" +
672  STR(fbb->CGetBBNodeInfo(bb_tgt)->block->number));
673  }
675  if(parameters->getOption<bool>(OPT_print_dot) && DEBUG_LEVEL_VERY_PEDANTIC <= debug_level)
676  {
677  HLS->STG->CGetStg()->WriteDot("HLS_STGraph-pre-opt.dot");
678  }
680  if(!parameters->IsParameter("fsm-duplication") || parameters->GetParameter<bool>("fsm-duplication"))
681  {
682  unsigned int instance = 0;
683  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Analyzing cycles");
684  BOOST_FOREACH(EdgeDescriptor fbbei, boost::edges(*fbb))
685  {
686  if(FB_CFG_SELECTOR & fbb->GetSelector(fbbei))
687  {
689  "-->Analyzing cycle starting from " +
690  STR(fbb->CGetBBNodeInfo(boost::source(fbbei, *fbb))->block->number) + "-->" +
691  STR(fbb->CGetBBNodeInfo(boost::target(fbbei, *fbb))->block->number));
692  const auto bbEndingCycle = boost::source(fbbei, *fbb);
693  // std::cerr << "begin cycles optimization" << std::endl;
694  optimize_cycles(bbEndingCycle, first_state, last_state, global_starting_ops, global_ending_ops,
695  global_executing_ops, global_onfly_ops);
696  // std::cerr << "end cycles optimization " << STR(instance) << std::endl;
697  if(parameters->getOption<bool>(OPT_print_dot) && DEBUG_LEVEL_VERY_PEDANTIC <= debug_level)
698  {
699  HLS->STG->CGetStg()->WriteDot("HLS_STGraph-post" + STR(instance) + ".dot");
700  }
701  ++instance;
703  "<--Analyzed cycle starting from " +
704  STR(fbb->CGetBBNodeInfo(boost::source(fbbei, *fbb))->block->number) + "-->" +
705  STR(fbb->CGetBBNodeInfo(boost::target(fbbei, *fbb))->block->number));
706  }
707  }
708  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Analyzed cycles");
709  }
710 
712 
713  HLS->STG->ComputeCyclesCount(is_pipelined);
714  HLS->registered_done_port = [&]() {
715  if(HLS->STG->CGetStg()->CGetStateTransitionGraphInfo()->min_cycles != 1 && !is_pipelined)
716  {
719  const auto exit_state = HLS->STG->get_exit_state();
720  BOOST_FOREACH(EdgeDescriptor ie, boost::in_edges(exit_state, *HLS->STG->CGetStg()))
721  {
722  const auto src_state = boost::source(ie, *HLS->STG->CGetStg());
723  if(HLS->STG->CGetStg()->CGetStateInfo(src_state)->is_dummy)
724  {
725  return false;
726  }
727  }
728  return true;
729  }
730  return false;
731  }();
733  {
735  }
737  "-->State Transition Graph Information of function " +
738  HLSMgr->CGetFunctionBehavior(funId)->CGetBehavioralHelper()->get_function_name() + ":");
741  "---Number of operations: " +
742  STR(boost::num_vertices(*(HLSMgr->CGetFunctionBehavior(funId)->CGetOpGraph(FunctionBehavior::CFG)))));
745  "---Number of basic blocks: " +
746  STR(boost::num_vertices(*(HLSMgr->CGetFunctionBehavior(funId)->CGetBBGraph(FunctionBehavior::BB)))));
748  if(has_registered_inputs)
749  {
750  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "---Parameters are registered");
751  }
752  if(HLS->registered_done_port || is_pipelined)
753  {
754  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "---Done port is registered");
755  }
756 
758  if(parameters->getOption<bool>(OPT_print_dot))
759  {
760  HLS->STG->CGetStg()->WriteDot("HLS_STGraph.dot");
761  HLS->STG->CGetStg()->WriteDot("fsm.dot", 1);
762  }
765  {
766  STOP_TIME(step_time);
767  }
769  {
771  "---Time to perform creation of STG: " + print_cpu_time(step_time) + " seconds");
772  }
774  {
776  }
778  {
779  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Checking BB graph - ST graph consistency");
780  CustomMap<unsigned int, ControlStep> bb_length, stg_length;
781  const auto st_graph = HLS->STG->CGetStg();
782  BOOST_FOREACH(vertex state, boost::vertices(*st_graph))
783  {
784  const auto state_info = st_graph->CGetStateInfo(state);
785  for(const auto BB_id : state_info->BB_ids)
786  {
787  if(stg_length.find(BB_id) != stg_length.end())
788  {
789  stg_length.at(BB_id)++;
790  }
791  else
792  {
793  stg_length.insert(CustomMap<unsigned int, ControlStep>::value_type(BB_id, ControlStep(1)));
794  }
795  }
796  }
797  const auto bb_cfg = HLSMgr->CGetFunctionBehavior(funId)->CGetBBGraph();
798  BOOST_FOREACH(vertex bb, boost::vertices(*bb_cfg))
799  {
800  const auto bb_node_info = bb_cfg->CGetBBNodeInfo(bb);
801  auto bb_begin = ControlStep(std::numeric_limits<unsigned int>::max());
802  auto bb_ending = ControlStep(0u);
803  for(const auto op : bb_node_info->statements_list)
804  {
805  if(HLS->Rsch->get_cstep(op).second < bb_begin)
806  {
807  bb_begin = HLS->Rsch->get_cstep(op).second;
808  }
809  if(HLS->Rsch->get_cstep_end(op).second > bb_ending)
810  {
811  bb_ending = HLS->Rsch->get_cstep_end(op).second;
812  }
813  }
814  bb_length.insert(
815  CustomMap<unsigned int, ControlStep>::value_type(bb_node_info->block->number, bb_ending - bb_begin + 1));
816  }
817 #ifndef NDEBUG
818  for(const auto& basic_block : bb_length)
819  {
821  "---BB" + STR(basic_block.first) + ": " +
822  STR(from_strongtype_cast<unsigned int>(basic_block.second)) + " vs. " +
823  STR(from_strongtype_cast<unsigned int>(stg_length.find(basic_block.first)->second)));
824  }
825 #endif
826  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Checked BB graph - ST graph consistency");
827  }
828  if(parameters->isOption(OPT_discrepancy_hw) && parameters->getOption<bool>(OPT_discrepancy_hw))
829  {
830  compute_EPP_edge_increments(global_starting_ops);
831  }
833 }
834 
836 {
837  const auto stg = STG->GetStg();
838  const auto entry_state = STG->get_entry_state();
839  THROW_ASSERT(boost::out_degree(entry_state, *stg) == 1, "entry state has not 1 successor");
840  const auto exit_state = STG->get_exit_state();
841  THROW_ASSERT(boost::in_degree(exit_state, *stg), "exit state has no predecessors");
842  /*
843  * Select pairs of vertices for which we have to add artificial edges for
844  * Efficient Path Profiling, to handle feedback edges.
845  * Dummy states are skipped, because they can be ignored.
846  */
849  BOOST_FOREACH(const vertex v, boost::vertices(*stg))
850  {
851  if(stg->CGetStateInfo(v)->is_dummy)
852  {
853  // skip dummies
854  continue;
855  }
856  BOOST_FOREACH(EdgeDescriptor oe, boost::out_edges(v, *stg))
857  {
858  if(stg->GetSelector(oe) & TransitionInfo::StateTransitionType::ST_EDGE_FEEDBACK)
859  {
860  epp_edges_to_add.insert(std::make_pair(v, exit_state));
861  }
862  }
863  BOOST_FOREACH(EdgeDescriptor ie, boost::in_edges(v, *stg))
864  if(stg->GetSelector(ie) & TransitionInfo::StateTransitionType::ST_EDGE_FEEDBACK)
865  {
866  epp_edges_to_add.insert(std::make_pair(entry_state, v));
867  }
868  }
869  for(const auto& e : epp_edges_to_add)
870  {
871  STG->STG_builder->connect_state(e.first, e.second, TransitionInfo::StateTransitionType::ST_EDGE_EPP);
872  }
873 }
874 
876 {
877  /*
878  * get the EPP stg, to avoid feedback edges
879  */
880  size_t res = 0;
881  const auto epp_stg = STG->GetEPPStg();
882  /*
883  * Execute the algorithm described in Figure 5 of the paper, to compute the
884  * edge increments. These increments are not definitive, because we have to
885  * propagate them on the feedback edges that are temporarily removed so that
886  * the algorithm can work properly.
887  */
889  std::deque<vertex> reverse_v_list;
890  epp_stg->ReverseTopologicalSort(reverse_v_list);
891  for(const auto v : reverse_v_list)
892  {
893  if(epp_stg->CGetStateInfo(v)->is_dummy)
894  {
895  /* dummy states are skipped */
896  continue;
897  }
898  if(boost::out_degree(v, *epp_stg) == 0) // is a leaf vertex
899  {
900  NumPaths[v] = 1;
901  }
902  else
903  {
904  size_t n = 0;
905  BOOST_FOREACH(EdgeDescriptor e, boost::out_edges(v, *epp_stg))
906  {
907  const auto selector = epp_stg->GetSelector(e);
908  const auto dst = boost::target(e, *epp_stg);
909  if(epp_stg->CGetStateInfo(dst)->is_dummy)
910  {
911  continue;
912  }
913  switch(selector)
914  {
915  case TransitionInfo::StateTransitionType::ST_EDGE_EPP:
916  case TransitionInfo::StateTransitionType::ST_EDGE_NORMAL:
917  epp_stg->GetTransitionInfo(e)->set_epp_increment(n);
918  n += NumPaths.at(dst);
919  break;
920  default:
921  THROW_UNREACHABLE("");
922  }
923  }
924  NumPaths[v] = n;
925  }
926  res = std::max(res, NumPaths.at(v));
927  }
928  return res;
929 }
930 
931 void BB_based_stg::compute_EPP_edge_increments(const std::map<vertex, std::list<vertex>>& starting_ops) const
932 {
933  const auto discr_info = HLSMgr->RDiscr->hw_discrepancy_info;
935  "-->Computing Efficient Path Profiling edge increments for HW discrepancy analysis");
936  INDENT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "-->Adding EPP edges");
938  INDENT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "<--Added EPP edges");
939  INDENT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "-->Computing EPP edge increments");
940  size_t max_path_val = compute_edge_increments(HLS->STG);
942  "<--Computed EPP edge increments: max_path_val = " + STR(max_path_val));
943  if(max_path_val)
944  {
945  size_t epp_trace_bitsize = 0;
946  do
947  {
948  epp_trace_bitsize++;
949  max_path_val >>= 1;
950  } while(max_path_val);
951  discr_info->fu_id_control_flow_skip.erase(funId);
953  "---fun id " + STR(funId) + "EPP path bits " + STR(epp_trace_bitsize));
954  discr_info->fu_id_to_epp_trace_bitsize[funId] = epp_trace_bitsize;
955  discr_info->fu_id_to_max_epp_path_val[funId] = max_path_val;
956  }
957  else
958  {
959  discr_info->fu_id_control_flow_skip.insert(funId);
960  discr_info->fu_id_to_epp_trace_bitsize[funId] = 0;
961  discr_info->fu_id_to_max_epp_path_val[funId] = 0;
962  INDENT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "---no control flow discrepancy is necessary");
963  }
964  INDENT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "-->Computing states where EPP trace must be checked");
965  auto& state_id_to_check = discr_info->fu_id_to_states_to_check[funId];
966  state_id_to_check.clear();
967  auto& state_id_to_check_on_feedback = discr_info->fu_id_to_feedback_states_to_check[funId];
968  state_id_to_check_on_feedback.clear();
969  auto& reset_edges = discr_info->fu_id_to_reset_edges[funId];
970  reset_edges.clear();
971  const auto& stg = HLS->STG->CGetStg();
972  const auto& stg_info = stg->CGetStateTransitionGraphInfo();
973  const auto dfgRef = HLSMgr->CGetFunctionBehavior(funId)->CGetOpGraph(FunctionBehavior::DFG);
974  for(const auto& state_to_op : starting_ops)
975  {
976  for(const auto& op : state_to_op.second)
977  {
978  const auto tn = HLS->allocation_information->get_fu(HLS->Rfu->get_assign(op));
979  const auto op_id = tree_helper::NormalizeTypename(dfgRef->CGetOpNodeInfo(op)->GetOperation());
980  const auto op_tn = GetPointer<const functional_unit>(tn)->get_operation(op_id);
981  if(!GetPointer<const operation>(op_tn)->is_bounded()) // TODO actual call, not unbounded
982  {
983  const auto state_id = stg_info->vertex_to_state_id.at(state_to_op.first);
985  "state: S_" + STR(state_id) +
986  " is always to check because it contains an unbounded operation");
987  state_id_to_check.insert(state_id);
988  }
989  }
990  }
991  BOOST_FOREACH(const EdgeDescriptor e, boost::edges(*stg))
992  {
993  if(stg->GetSelector(e) & TransitionInfo::StateTransitionType::ST_EDGE_FEEDBACK)
994  {
995 #if HAVE_ASSERTS || !defined(NDEBUG)
996  const auto src = boost::source(e, *stg);
997 #endif
998  const auto dst = boost::target(e, *stg);
999  const bool dst_dummy = stg->CGetStateInfo(dst)->is_dummy;
1000  if(!dst_dummy)
1001  {
1002  const auto dst_state_id = stg_info->vertex_to_state_id.at(dst);
1004  "state: S_" + STR(dst_state_id) +
1005  " is to check on feedback because it is the destination of a feedback edge");
1006  state_id_to_check_on_feedback.insert(dst_state_id);
1008  "edge from state: S_" + STR(stg_info->vertex_to_state_id.at(src)) + " to state: S_" +
1009  STR(dst_state_id) + " is to reset");
1010  reset_edges.insert(e);
1011  }
1012  else
1013  {
1014  THROW_ASSERT(stg->CGetStateInfo(src)->is_dummy and (src == dst), "");
1015  }
1016  }
1017  }
1018  const auto exit_state = stg_info->exit_node;
1019  BOOST_FOREACH(const EdgeDescriptor in_e, boost::in_edges(exit_state, *stg))
1020  {
1021  const auto src = boost::source(in_e, *stg);
1022  const bool src_dummy = stg->CGetStateInfo(src)->is_dummy;
1023  if(!src_dummy)
1024  {
1025  const auto state_id = stg_info->vertex_to_state_id.at(src);
1027  "state: S_" + STR(state_id) + " is always to check because it is before end state");
1028  state_id_to_check.insert(state_id);
1029  }
1030  }
1031  INDENT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "<--Computed states where EPP trace must be checked");
1033  "<--Computed Efficient Path Profiling edge increments for HW discrepancy analysis");
1034  if(parameters->getOption<bool>(OPT_print_dot))
1035  {
1036  stg->WriteDot("STG_EPP.dot");
1037  HLS->STG->CGetEPPStg()->WriteDot("EPP.dot");
1038  }
1039  return;
1040 }
1041 
1049  std::map<vertex, std::list<vertex>>& global_starting_ops,
1050  std::map<vertex, std::list<vertex>>& global_ending_ops,
1051  std::map<vertex, std::list<vertex>>& global_executing_ops,
1052  std::map<vertex, std::list<vertex>>& global_onfly_ops)
1053 {
1054  const auto fbb = HLSMgr->CGetFunctionBehavior(funId)->CGetBBGraph(FunctionBehavior::FBB);
1056  "Considering bbEndingCycle:" + STR(fbb->CGetBBNodeInfo(bbEndingCycle)->block->number));
1057  std::list<vertex>::iterator it, findIter;
1058  // The last state of the cycle
1059  const auto stg = HLS->STG->CGetStg();
1060  const auto lastst = last_state[bbEndingCycle];
1061  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Last state is " + stg->CGetStateInfo(lastst)->name);
1062  if(stg->CGetStateInfo(lastst)->is_duplicated)
1063  {
1064  return;
1065  }
1066  if(boost::in_degree(lastst, *stg) != 1)
1067  {
1068  return;
1069  }
1070 
1071  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Compute the second last state of the bb");
1072  /*
1073  Compute the second last state of the bb. After the move,
1074  this state will become the last state of the bb.
1075  */
1076  const auto secondLastState = boost::source(*(boost::in_edges(lastst, *stg).first), *stg);
1077  if(stg->CGetStateInfo(secondLastState)->is_dummy)
1078  {
1079  return;
1080  }
1082  "Second last state computed " + stg->CGetStateInfo(secondLastState)->name);
1083 
1084  BOOST_FOREACH(EdgeDescriptor oedge, boost::out_edges(lastst, *stg))
1085  {
1086  const auto cstate = boost::target(oedge, *stg);
1087  if(stg->CGetStateInfo(cstate)->is_duplicated)
1088  {
1089  return;
1090  }
1091  }
1092  // std::cerr << "considering this last state " << stg->CGetStateInfo(lastst)->name << std::endl;
1093  // All the functions called in the last cycle
1094  std::list<vertex> lastStateStartingOpList = global_starting_ops[lastst];
1095  // All the operations that need input in the last cycle
1096  std::list<vertex> lastStateExecutingOpList = global_executing_ops[lastst];
1097  // All the operations ending in the last cycle
1098  std::list<vertex> lastStateEndingOpList = global_ending_ops[lastst];
1099  // All the operations already running at the beginning of the last cycle
1100  std::list<vertex> lastStateOnFlyOpList = global_onfly_ops[lastst];
1101  // All the "conditional operations" in the last state
1102  std::list<vertex> lastStateConditionalOpList;
1103 
1104  if(lastStateEndingOpList.size() == 1)
1105  {
1106  return;
1107  }
1108  // If the bb is composed by just one state, it is not possible to optimize
1109  if(first_state[bbEndingCycle] == last_state[bbEndingCycle])
1110  {
1111  return;
1112  }
1113 
1114  /*
1115  If an operation starts and does not end in the final state,
1116  the optimization is complete. Any further optimization will
1117  require rescheduling.
1118  */
1119  for(it = lastStateStartingOpList.begin(); it != lastStateStartingOpList.end(); ++it)
1120  {
1121  findIter = std::find(lastStateEndingOpList.begin(), lastStateEndingOpList.end(), *it);
1122  if(findIter == lastStateEndingOpList.end())
1123  {
1124  return;
1125  }
1126  }
1127  for(it = lastStateExecutingOpList.begin(); it != lastStateExecutingOpList.end(); ++it)
1128  {
1129  findIter = std::find(lastStateEndingOpList.begin(), lastStateEndingOpList.end(), *it);
1130  if(findIter == lastStateEndingOpList.end())
1131  {
1132  return;
1133  }
1134  }
1135  for(it = lastStateOnFlyOpList.begin(); it != lastStateOnFlyOpList.end(); ++it)
1136  {
1137  findIter = std::find(lastStateEndingOpList.begin(), lastStateEndingOpList.end(), *it);
1138  if(findIter == lastStateEndingOpList.end())
1139  {
1140  return;
1141  }
1142  }
1143  /*************************************************************
1144  From now on, lastStateEndingOpList can be considered a list
1145  containing all the operations of the state.
1146  *************************************************************/
1147  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Basic checks passed");
1148  /*
1149  Some operations cannot be moved in any case. If any of them
1150  is executed in the last state, I have to return without performing
1151  any optimization.
1152  In addition to this, operations chained to conditional operations
1153  cannot be moved.
1154  */
1155  bool has_STOREs = false;
1156  const auto dfgRef = HLSMgr->CGetFunctionBehavior(funId)->CGetOpGraph(FunctionBehavior::DFG);
1157  for(it = lastStateEndingOpList.begin(); it != lastStateEndingOpList.end(); ++it)
1158  {
1160  // phi operators cannot be moved
1161  if(GET_TYPE(dfgRef, *it) & (TYPE_PHI | TYPE_VPHI))
1162  {
1163  return;
1164  }
1166  if(GET_TYPE(dfgRef, *it) & TYPE_RET)
1167  {
1168  return;
1169  }
1170  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Check switch and multi-if");
1171  // creates a list containing all the conditional operations
1172  if(GET_TYPE(dfgRef, *it) & (TYPE_IF))
1173  {
1174  lastStateConditionalOpList.push_back(*it);
1175  }
1176  else if(GET_TYPE(dfgRef, *it) & (TYPE_MULTIIF))
1177  {
1178  return; // lastStateConditionalOpList.push_back(*it);
1179  }
1180  else if(GET_TYPE(dfgRef, *it) & (TYPE_SWITCH))
1181  {
1182  return; // lastStateConditionalOpList.push_back(*it);
1183  }
1184 
1186  const auto fu_id = HLS->Rfu->get_assign(*it);
1189  {
1190  return;
1191  }
1192  if(parameters->getOption<bool>(OPT_disable_function_proxy) &&
1194  {
1195  return;
1196  }
1197  const auto tn = HLS->allocation_information->get_fu(fu_id);
1198  const auto op_tn = GetPointer<functional_unit>(tn)->get_operation(
1199  tree_helper::NormalizeTypename(dfgRef->CGetOpNodeInfo(*it)->GetOperation()));
1200  if(!GetPointer<operation>(op_tn)->is_bounded())
1201  {
1202  return;
1203  }
1204 
1205  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Check multi-cycle");
1206  if(GetPointer<operation>(op_tn)->time_m->get_cycles() > 1)
1207  {
1208  return;
1209  }
1210 
1211  if(GET_TYPE(dfgRef, *it) & TYPE_STORE)
1212  {
1213  has_STOREs = true;
1214  }
1215 
1216  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Check resource-constrained");
1217  // operations executed by resource-constrained fu should not be moved
1218  if(res_const_operation(*it, lastStateExecutingOpList, lastst))
1219  {
1221  "Resource constraints limit on operation " + dfgRef->CGetOpNodeInfo(*it)->GetOperation());
1222  return;
1223  }
1224 
1225  /*
1226  check if the operation is chained to a conditional operation:
1227  in this case, I cannot optimize.
1228  */
1229  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Check data dependency with control operation");
1230  BOOST_FOREACH(EdgeDescriptor ei, boost::out_edges(*it, *dfgRef))
1231  {
1232  const auto tgt_op = boost::target(ei, *dfgRef);
1233  if(std::find(lastStateExecutingOpList.begin(), lastStateExecutingOpList.end(), tgt_op) ==
1234  lastStateExecutingOpList.end())
1235  {
1236  continue;
1237  }
1238  if(GET_TYPE(dfgRef, tgt_op) & (TYPE_IF))
1239  {
1241  return;
1242  }
1243  if(GET_TYPE(dfgRef, tgt_op) & (TYPE_MULTIIF))
1244  {
1245  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "depending multi if");
1246  return;
1247  }
1248  if(GET_TYPE(dfgRef, tgt_op) & (TYPE_SWITCH))
1249  {
1251  return;
1252  }
1253  }
1254  }
1255 
1256  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Creating list of following bb");
1257  /*
1258  Create a list of all the bb following the last bb of the cycle
1259  that I am optimizing.
1260  */
1261  std::list<vertex> followingBb;
1262  vertex tempBb;
1263 
1264  BOOST_FOREACH(EdgeDescriptor ei, boost::out_edges(bbEndingCycle, *fbb))
1265  {
1266  tempBb = boost::target(ei, *fbb);
1270 
1271  if(tempBb == fbb->CGetBBGraphInfo()->exit_vertex)
1272  {
1273  return;
1274  }
1275  if(bbEndingCycle == tempBb)
1276  {
1277  followingBb.push_back(tempBb);
1278  }
1279  else
1280  {
1281  followingBb.push_front(tempBb);
1282  }
1283  if(has_STOREs)
1284  {
1285  for(auto next_ops : global_starting_ops[first_state[tempBb]])
1286  {
1287  const auto operation = dfgRef->CGetOpNodeInfo(next_ops);
1288  auto curr_vertex_type = GET_TYPE(dfgRef, next_ops);
1289  if((curr_vertex_type & (TYPE_STORE | TYPE_LOAD)) != 0)
1290  {
1291  return;
1292  }
1293  if((curr_vertex_type & TYPE_EXTERNAL) && (curr_vertex_type & TYPE_RW))
1294  {
1295  return;
1296  }
1297  }
1298  }
1299  else
1300  {
1301  for(auto next_ops : global_starting_ops[first_state[tempBb]])
1302  {
1303  if((GET_TYPE(dfgRef, next_ops) & TYPE_MULTIIF))
1304  {
1305  return;
1306  }
1307  }
1308  }
1309  // std::cerr << fbb->CGetBBNodeInfo(tempBb)->get_bb_index() << std::endl;
1310  }
1311 
1312  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "check if it is possible to move the last state");
1313  /*
1314  check if it is possible to move the last state of the cycle at the beginning
1315  of every adjacent bb.
1316  */
1317  for(auto bbVertex : followingBb)
1318  {
1319  if(!can_be_moved(lastStateEndingOpList, lastStateConditionalOpList, first_state[bbVertex], global_starting_ops,
1320  global_executing_ops))
1321  {
1322  return;
1323  }
1324  }
1325 
1326  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "compute which variables are defined and used");
1327  /*
1328  compute which variables are defined and used by the operations that will be
1329  moved, and check that it is possible to store in registers all the used variables
1330  */
1331  CustomOrderedSet<unsigned int> useSet, defSet;
1332  compute_use_def(lastStateEndingOpList, lastStateExecutingOpList, lastStateConditionalOpList, useSet, defSet, dfgRef);
1333 
1334  /*
1335  * check if destination states define a variable in the useSet
1336  * This check is required by the current interconnection algorithm
1337  */
1338  bool is_dest_first_st_equal_to_second = false;
1339  for(auto bbVertex : followingBb)
1340  {
1341  vertex dest_first_state = first_state[bbVertex];
1342  if(dest_first_state == secondLastState)
1343  {
1344  is_dest_first_st_equal_to_second = true;
1345  break;
1346  }
1347  }
1348  if(is_dest_first_st_equal_to_second)
1349  {
1350  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "is_dest_first_st_equal_to_second is true!");
1351  }
1352  for(auto bbVertex : followingBb)
1353  {
1354  vertex dest_first_state = first_state[bbVertex];
1355  bool skip_phi = true;
1356  if(boost::in_degree(dest_first_state, *stg) > 1)
1357  {
1358  if(!is_dest_first_st_equal_to_second)
1359  {
1360  BOOST_FOREACH(EdgeDescriptor prev_edge, boost::out_edges(dest_first_state, *stg))
1361  {
1362  const auto next_state = boost::target(prev_edge, *stg);
1363  if(next_state == dest_first_state)
1364  {
1365  skip_phi = false;
1366  break;
1367  }
1368  }
1369  }
1370  else
1371  {
1372  if(dest_first_state != secondLastState)
1373  {
1374  skip_phi = false;
1375  }
1376  }
1377  }
1378  if(skip_phi)
1379  {
1380  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Phi can be skipped!");
1381  }
1382  for(auto stmt : global_ending_ops[dest_first_state])
1383  {
1384  if(skip_phi && (GET_TYPE(dfgRef, stmt) & TYPE_PHI))
1385  {
1386  continue;
1387  }
1388  if(GET_TYPE(dfgRef, stmt) & (TYPE_VPHI))
1389  {
1390  continue;
1391  }
1392  const CustomSet<unsigned int>& scalar_defs = dfgRef->CGetOpNodeInfo(stmt)->GetVariables(
1394  if(not scalar_defs.empty())
1395  {
1396  for(auto tree_var : scalar_defs)
1397  {
1398  if(HLSMgr->is_register_compatible(tree_var) && useSet.find(tree_var) != useSet.end())
1399  {
1400  return;
1401  }
1402  }
1403  }
1404  }
1405  }
1406  std::map<vertex, std::size_t> in_degree_following_Bb;
1408  for(auto bbVertex : followingBb)
1409  {
1410  in_degree_following_Bb[bbVertex] = boost::in_degree(first_state[bbVertex], *stg);
1411  if(in_degree_following_Bb[bbVertex] > 2)
1412  {
1413  return;
1414  }
1416  if(in_degree_following_Bb[bbVertex] > 1)
1417  {
1419  "src state:" + stg->CGetStateInfo(first_state[bbVertex])->name);
1420  BOOST_FOREACH(EdgeDescriptor oedge, boost::out_edges(first_state[bbVertex], *stg))
1421  {
1422  const auto cstate = boost::target(oedge, *stg);
1423  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "target state:" + stg->CGetStateInfo(cstate)->name);
1424  if(stg->CGetStateInfo(cstate)->is_dummy)
1425  {
1426  return;
1427  }
1428  }
1429  }
1430  }
1431 
1432  for(auto bbVertex : followingBb)
1433  {
1435  "analyzing BB:" + STR(fbb->CGetBBNodeInfo(bbVertex)->block->number));
1437  "first state:" + stg->CGetStateInfo(first_state[bbVertex])->name);
1439  "last state:" + stg->CGetStateInfo(last_state[bbVertex])->name);
1440  if(last_state[bbVertex] == first_state[bbVertex])
1441  {
1442  BOOST_FOREACH(EdgeDescriptor ei, boost::out_edges(bbVertex, *fbb))
1443  {
1444  const auto tgtBB = boost::target(ei, *fbb);
1446  "target BB:" + STR(fbb->CGetBBNodeInfo(tgtBB)->block->number));
1447  if(boost::in_degree(first_state[tgtBB], *stg) > 1)
1448  {
1449  return;
1450  }
1451  }
1452  }
1453  }
1454  /********************************************************
1455  If I arrive here, it is possible to move the last state
1456  *********************************************************/
1457  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "One state can be moved!");
1458 
1459  /*
1460  Move all the conditional operations from the last state to
1461  the second last state, removing them from lastState...OpList.
1462  There is no need of removing these operations form the vertex
1463  representing the last state in the STG, since that state will
1464  be deleted later in this method.
1465  */
1466  const auto wstg = HLS->STG->GetStg();
1467  for(auto ops : lastStateConditionalOpList)
1468  {
1469  // update global_... maps
1470  global_starting_ops[lastst].remove(ops);
1471  global_executing_ops[lastst].remove(ops);
1472  global_ending_ops[lastst].remove(ops);
1473  global_starting_ops[secondLastState].push_back(ops);
1474  global_executing_ops[secondLastState].push_back(ops);
1475  global_ending_ops[secondLastState].push_back(ops);
1476  // update the second last state in the STG
1477  wstg->GetStateInfo(secondLastState)->starting_operations.push_back(ops);
1478  wstg->GetStateInfo(secondLastState)->executing_operations.push_back(ops);
1479  wstg->GetStateInfo(secondLastState)->ending_operations.push_back(ops);
1480  }
1481 
1482  /*
1483  Move all the non-conditional operations to the first state of the following bbs
1484  */
1485  for(auto bbVertex : followingBb)
1486  {
1488  "analyzing BB:" + STR(fbb->CGetBBNodeInfo(bbVertex)->block->number));
1489  if(in_degree_following_Bb[bbVertex] > 1)
1490  {
1491  move_with_duplication(lastst, secondLastState, first_state[bbVertex], global_starting_ops,
1492  global_executing_ops, global_ending_ops, defSet, useSet);
1493  }
1494  else
1495  {
1496  move_without_duplication(lastst, secondLastState, first_state[bbVertex], global_starting_ops,
1497  global_executing_ops, global_ending_ops, defSet, useSet);
1498  }
1499  }
1500 
1501  /***********************************************************
1502  Now I can delete the last state of the bb ending the cycle,
1503  and all the edges entering and exiting from it
1504  **********************************************************/
1505  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Deleting the last state of the cycle..");
1506  /*
1507  update the last_state map
1508  */
1509  last_state[bbEndingCycle] = secondLastState;
1510  /*
1511  delete the edge entering the last state
1512  */
1513  HLS->STG->STG_builder->delete_edge(secondLastState, lastst);
1514  // std::cerr << "deleting egde " << stg->CGetStateInfo(secondLastState)->name << "->" <<
1515  // stg->CGetStateInfo(lastst)->name << std::endl;
1516  /*
1517  delete all the edges exiting the last state
1518  */
1519  std::list<vertex> linkedStates;
1520  BOOST_FOREACH(EdgeDescriptor oedge, boost::out_edges(lastst, *stg))
1521  {
1522  const auto cstate = boost::target(oedge, *stg);
1523  linkedStates.push_back(cstate);
1524  }
1525  for(auto cstate : linkedStates)
1526  {
1527  HLS->STG->STG_builder->delete_edge(lastst, cstate);
1528  // std::cerr << "deleting egde " << stg->CGetStateInfo(lastst)->name << "->" << stg->CGetStateInfo(*its)->name <<
1529  // std::endl;
1530  }
1531 
1532  // std::cerr << "deleting " << stg->CGetStateInfo(lastst)->name << std::endl;
1533  /*
1534  delete the last state
1535  */
1536  HLS->STG->STG_builder->delete_state(lastst);
1537 
1538  return;
1539 }
1540 
1549 bool BB_based_stg::can_be_moved(std::list<vertex>& lastStateEndingOp, std::list<vertex>& lastStateConditionalOpList,
1550  vertex firstStateNextBb, std::map<vertex, std::list<vertex>>& global_starting_ops,
1551  std::map<vertex, std::list<vertex>>& global_executing_ops)
1552 {
1553  vertex tempDependentOp;
1554  std::list<vertex>::iterator it, findIter;
1555 
1556  for(it = lastStateEndingOp.begin(); it != lastStateEndingOp.end(); ++it)
1557  {
1558  findIter = std::find(lastStateConditionalOpList.begin(), lastStateConditionalOpList.end(), *it);
1559  /*
1560  conditional operations should not be considered in this analysis,
1561  because they will be moved in a different way.
1562  */
1563  if(findIter == lastStateConditionalOpList.end())
1564  {
1566  {
1567  continue; // instantaneous operations can always be moved
1568  }
1569  tempDependentOp = check_data_dependency(*it, firstStateNextBb, global_starting_ops, global_executing_ops);
1570  if(tempDependentOp == nullptr)
1571  {
1572  continue; // no data dependency, it is possible to move that operation
1573  }
1574  if(is_instantaneous_operation(tempDependentOp))
1575  {
1576  continue; /* the operation will be chained to an instantaneous operation,
1577  in the destination state, so it is possible to move it */
1578  }
1579  return false; // data dependencies prevent this operation from being moved
1580  }
1581  }
1582  return true;
1583 }
1584 
1600  std::map<vertex, std::list<vertex>>& global_starting_ops,
1601  std::map<vertex, std::list<vertex>>& global_executing_ops)
1602 {
1603  std::list<vertex> StartingOpList = global_starting_ops[state];
1604  std::list<vertex> ExecutingOpList = global_executing_ops[state];
1605  std::list<vertex>::iterator it;
1606  vertex dependentOperation;
1607 
1608  for(it = StartingOpList.begin(); it != StartingOpList.end(); ++it)
1609  {
1610  if(HLSMgr->CGetFunctionBehavior(funId)->CGetOpGraph(FunctionBehavior::DFG)->ExistsEdge(operation, *it))
1611  {
1613  {
1614  dependentOperation = check_data_dependency(*it, state, global_starting_ops, global_executing_ops);
1615  if(dependentOperation != nullptr)
1616  {
1617  return dependentOperation;
1618  }
1619  }
1620  return *it;
1621  }
1622  }
1623 
1624  for(it = ExecutingOpList.begin(); it != ExecutingOpList.end(); ++it)
1625  {
1626  if(HLSMgr->CGetFunctionBehavior(funId)->CGetOpGraph(FunctionBehavior::DFG)->ExistsEdge(operation, *it))
1627  {
1629  {
1630  dependentOperation = check_data_dependency(*it, state, global_starting_ops, global_executing_ops);
1631  if(dependentOperation != nullptr)
1632  {
1633  return dependentOperation;
1634  }
1635  }
1636  return *it;
1637  }
1638  }
1639 
1640  return nullptr;
1641 }
1642 
1647 {
1648  const auto dfgRef = HLSMgr->CGetFunctionBehavior(funId)->CGetOpGraph(FunctionBehavior::DFG);
1649 
1650  // The operation is a phi
1651  if(GET_TYPE(dfgRef, operation) & (TYPE_PHI))
1652  {
1653  return true;
1654  }
1655  const auto op = dfgRef->CGetOpNodeInfo(operation)->GetOperation();
1656  if(op == ASSIGN || op == NOP_EXPR || op == CONVERT_EXPR || op == VIEW_CONVERT_EXPR)
1657  {
1658  return true;
1659  }
1660 
1661  return false;
1662 }
1663 
1668 bool BB_based_stg::res_const_operation(vertex& operation, std::list<vertex>& lastStateExecutingOpList, vertex lastst)
1669 {
1670  unsigned int currentUnitID = HLS->Rfu->get_assign(operation);
1671  if(HLS->allocation_information->get_number_fu(currentUnitID) == INFINITE_UINT)
1672  {
1673  return false;
1674  }
1675 
1676  /*
1677  * if the number of fu of that type is limited, we have to
1678  * make sure that it is feasible to move that
1679  * operation in the following states
1680  */
1681  unsigned int currentlyNeededUnit = 0;
1682 
1683  for(auto tempOp : lastStateExecutingOpList)
1684  {
1685  if(currentUnitID == HLS->Rfu->get_assign(tempOp))
1686  {
1687  currentlyNeededUnit++;
1688  }
1689  }
1690  const auto stg = HLS->STG->CGetStg();
1691  BOOST_FOREACH(EdgeDescriptor oedge, boost::out_edges(lastst, *stg))
1692  {
1693  const auto tempSt = boost::target(oedge, *stg);
1694  unsigned int tempNeededUnit = 0;
1695  for(auto tempOp : HLS->STG->GetStg()->GetStateInfo(tempSt)->executing_operations)
1696  {
1697  if(currentUnitID == HLS->Rfu->get_assign(tempOp))
1698  {
1699  tempNeededUnit++;
1700  }
1701  }
1702  if(tempNeededUnit + currentlyNeededUnit > HLS->allocation_information->get_number_fu(currentUnitID))
1703  {
1704  return true;
1705  }
1706  }
1707 
1708  return false;
1709 }
1710 
1718 void BB_based_stg::compute_use_def(const std::list<vertex>& opEndingList, const std::list<vertex>& opRuningList,
1719  const std::list<vertex>& ignoreList, CustomOrderedSet<unsigned int>& useSet,
1720  CustomOrderedSet<unsigned int>& defSet, const OpGraphConstRef data)
1721 {
1722  /*
1723  Clear useSet and defSet
1724  */
1725  useSet.clear();
1726  defSet.clear();
1727 
1728  /*
1729  For each operation, I get the lista of SSA variables used and
1730  defined, and I update useSet and defSet
1731  */
1732 
1733  for(const auto cur_op : opEndingList)
1734  {
1735  if(std::find(ignoreList.begin(), ignoreList.end(), cur_op) != ignoreList.end())
1736  {
1737  continue;
1738  }
1739 
1740  const CustomSet<unsigned int>& scalar_defs = data->CGetOpNodeInfo(cur_op)->GetVariables(
1742 
1743  for(auto tree_var : scalar_defs)
1744  {
1745  if(HLSMgr->is_register_compatible(tree_var))
1746  {
1747  defSet.insert(tree_var);
1748  }
1749  }
1750  }
1751 
1752  for(const auto cur_op : opRuningList)
1753  {
1754  if(std::find(ignoreList.begin(), ignoreList.end(), cur_op) != ignoreList.end())
1755  {
1756  continue;
1757  }
1758 
1759  const CustomSet<unsigned int>& scalar_uses = data->CGetOpNodeInfo(cur_op)->GetVariables(
1761 
1762  for(auto tree_var : scalar_uses)
1763  {
1764  if(HLSMgr->is_register_compatible(tree_var) and defSet.find(tree_var) == defSet.end())
1765  {
1766  useSet.insert(tree_var);
1767  }
1768  }
1769  }
1770 
1771  return;
1772 }
1773 
1779 void BB_based_stg::move_without_duplication(const vertex stateToMove, const vertex secondLastState,
1780  const vertex destinationState,
1781  const std::map<vertex, std::list<vertex>>& global_starting_ops,
1782  const std::map<vertex, std::list<vertex>>& global_executing_ops,
1783  const std::map<vertex, std::list<vertex>>& global_ending_ops,
1784  const CustomOrderedSet<unsigned int>& defSet,
1785  const CustomOrderedSet<unsigned int>& useSet)
1786 {
1787  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Moving without duplication");
1788  const auto STGMan = HLS->STG;
1789  const auto stg = STGMan->GetStg();
1791  "moving operations from state: " + STGMan->get_state_name(stateToMove));
1793  "moving operations to state: " + STGMan->get_state_name(destinationState));
1795  "second last state: " + STGMan->get_state_name(secondLastState));
1796  const auto dstStateInfo = stg->GetStateInfo(destinationState);
1797  dstStateInfo->moved_op_use_set = useSet;
1798  dstStateInfo->moved_op_def_set = defSet;
1799  /*
1800  * copy in the destination state all the operations that are
1801  * executed in the state to move.
1802  */
1803  {
1804  const auto op_it = global_executing_ops.find(stateToMove);
1805  if(op_it != global_executing_ops.end())
1806  {
1807  BOOST_REVERSE_FOREACH(vertex operation, op_it->second)
1808  {
1809  dstStateInfo->executing_operations.push_front(operation);
1810  dstStateInfo->moved_exec_op.push_front(operation);
1811  }
1812  }
1813  }
1814  {
1815  const auto op_it = global_starting_ops.find(stateToMove);
1816  if(op_it != global_starting_ops.end())
1817  {
1818  BOOST_REVERSE_FOREACH(vertex operation, op_it->second)
1819  {
1820  dstStateInfo->starting_operations.push_front(operation);
1821  }
1822  }
1823  }
1824  {
1825  const auto op_it = global_ending_ops.find(stateToMove);
1826  if(op_it != global_ending_ops.end())
1827  {
1828  BOOST_REVERSE_FOREACH(vertex operation, op_it->second)
1829  {
1830  dstStateInfo->ending_operations.push_front(operation);
1831  dstStateInfo->moved_ending_op.push_front(operation);
1832  }
1833  }
1834  }
1835  /*
1836  * create an edge from the second last state to the new state
1837  */
1838  EdgeDescriptor linkingEdge = stg->CGetEdge(stateToMove, destinationState);
1840  "existing edge: " + STGMan->get_state_name(stateToMove) + "->" +
1841  STGMan->get_state_name(destinationState));
1842  EdgeDescriptor newEdge =
1843  HLS->STG->STG_builder->connect_state(secondLastState, destinationState, stg->GetSelector(linkingEdge));
1844  HLS->STG->STG_builder->copy_condition(newEdge, linkingEdge);
1846  "new edge: " + STGMan->get_state_name(secondLastState) + "->" +
1847  STGMan->get_state_name(destinationState));
1848 
1849  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Moved without duplication");
1850  return;
1851 }
1852 
1860 void BB_based_stg::move_with_duplication(const vertex stateToMove, const vertex secondLastState,
1861  const vertex stateToClone,
1862  const std::map<vertex, std::list<vertex>>& global_starting_ops,
1863  const std::map<vertex, std::list<vertex>>& global_executing_ops,
1864  const std::map<vertex, std::list<vertex>>& global_ending_ops,
1865  const CustomOrderedSet<unsigned int>& defSet,
1866  const CustomOrderedSet<unsigned int>& useSet)
1867 {
1868  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Moving with duplication");
1869  const auto stg = HLS->STG->GetStg();
1870  const auto toMoveStateInfo = stg->GetStateInfo(stateToMove);
1871  const auto toCloneStateInfo = stg->GetStateInfo(stateToClone);
1872  const auto secondLastStateInfo = stg->GetStateInfo(secondLastState);
1873  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "moving operations from state: " + toMoveStateInfo->name);
1875  "moving operations to state: " + toCloneStateInfo->name + " that will be cloned");
1876  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "second last state: " + secondLastStateInfo->name);
1877  unsigned int currentBbID = *toMoveStateInfo->BB_ids.begin();
1878  /*
1879  * clone the first state of the destination bb
1880  */
1881  const auto clonedState = HLS->STG->STG_builder->create_state(
1882  toCloneStateInfo->executing_operations, toCloneStateInfo->starting_operations,
1883  toCloneStateInfo->ending_operations, toCloneStateInfo->BB_ids);
1884  // set is_duplicated to true, and saves info about the source Bb of the data
1885  const auto clonedStateInfo = stg->GetStateInfo(clonedState);
1886  clonedStateInfo->is_duplicated = true;
1887  clonedStateInfo->sourceBb = currentBbID;
1888  clonedStateInfo->clonedState = stateToClone;
1889  clonedStateInfo->moved_op_def_set = defSet;
1890  clonedStateInfo->moved_op_use_set = useSet;
1891  toCloneStateInfo->is_duplicated = true;
1892  toCloneStateInfo->isOriginalState = true;
1893  toCloneStateInfo->sourceBb = currentBbID;
1894 
1896  "cloned state: " + toCloneStateInfo->name + " new clone: " + clonedStateInfo->name);
1897 
1898  {
1899  const auto op_it = global_executing_ops.find(stateToMove);
1900  if(op_it != global_executing_ops.end())
1901  {
1902  BOOST_REVERSE_FOREACH(vertex operation, op_it->second)
1903  {
1904  clonedStateInfo->executing_operations.push_front(operation);
1905  clonedStateInfo->moved_exec_op.push_front(operation);
1906  }
1907  }
1908  }
1909  {
1910  const auto op_it = global_starting_ops.find(stateToMove);
1911  if(op_it != global_starting_ops.end())
1912  {
1913  BOOST_REVERSE_FOREACH(vertex operation, op_it->second)
1914  {
1915  clonedStateInfo->starting_operations.push_front(operation);
1916  }
1917  }
1918  }
1919  {
1920  const auto op_it = global_ending_ops.find(stateToMove);
1921  if(op_it != global_ending_ops.end())
1922  {
1923  BOOST_REVERSE_FOREACH(vertex operation, op_it->second)
1924  {
1925  clonedStateInfo->ending_operations.push_front(operation);
1926  clonedStateInfo->moved_ending_op.push_front(operation);
1927  }
1928  }
1929  }
1930 
1931  /*
1932  * create a NORMAL edge from the second last state to the new state, and set the conditions
1933  */
1934  EdgeDescriptor linkingEdge = stg->CGetEdge(stateToMove, stateToClone);
1936  "existing edge: " + toMoveStateInfo->name + "->" + toCloneStateInfo->name);
1937  EdgeDescriptor newEdge = HLS->STG->STG_builder->connect_state(
1938  secondLastState, clonedState,
1939  stateToClone != secondLastState ? stg->GetSelector(linkingEdge) :
1940  TransitionInfo::StateTransitionType::ST_EDGE_NORMAL);
1941  HLS->STG->STG_builder->copy_condition(newEdge, linkingEdge);
1943  "new edge: " + secondLastStateInfo->name + "->" + clonedStateInfo->name);
1944  /*
1945  * create an edge from the the new state to every state that
1946  * follows the first state of the destination bb
1947  */
1948  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "state to clone: " + toCloneStateInfo->name);
1949  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "second last state: " + secondLastStateInfo->name);
1950  if(stateToClone != secondLastState)
1951  {
1952  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "state to clone != second last state");
1953  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Considering successors of state to clone");
1954  BOOST_FOREACH(EdgeDescriptor oe, boost::out_edges(stateToClone, *stg))
1955  {
1956  const auto successor = boost::target(oe, *stg);
1957  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->successor: " + stg->CGetStateInfo(successor)->name);
1958  THROW_ASSERT(successor != stateToMove, "unexpected case");
1959  const auto new_successor = ((successor == stateToMove) ? clonedState : successor);
1961  "new successor: " + stg->CGetStateInfo(new_successor)->name);
1962  EdgeDescriptor new_edge =
1963  HLS->STG->STG_builder->connect_state(clonedState, new_successor, stg->GetSelector(oe));
1964  HLS->STG->STG_builder->copy_condition(new_edge, oe);
1966  "new edge: " + clonedStateInfo->name + "->" + stg->CGetStateInfo(new_successor)->name);
1967  if(successor == stateToClone)
1968  {
1969  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "successor: " + stg->CGetStateInfo(successor)->name);
1970  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "state to clone: " + toCloneStateInfo->name);
1972  "all path for " + stg->CGetStateInfo(successor)->name + " set to true");
1973  stg->GetStateInfo(successor)->all_paths = true;
1974  }
1976  }
1978  }
1979  else
1980  {
1981  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "state to clone == second last state");
1982  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Considering successors of state to clone");
1983  BOOST_FOREACH(EdgeDescriptor oe, boost::out_edges(stateToClone, *stg))
1984  {
1985  const auto successor = boost::target(oe, *stg);
1986  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->successor: " + stg->CGetStateInfo(successor)->name);
1987  if(successor == stateToMove)
1988  {
1989  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--state to move : " + toMoveStateInfo->name);
1990  continue;
1991  }
1992  const auto sel =
1993  successor != clonedState ? stg->GetSelector(oe) : TransitionInfo::StateTransitionType::ST_EDGE_FEEDBACK;
1994  EdgeDescriptor new_edge = HLS->STG->STG_builder->connect_state(clonedState, successor, sel);
1995  HLS->STG->STG_builder->copy_condition(new_edge, oe);
1997  "new edge: " + clonedStateInfo->name + "->" + stg->GetStateInfo(successor)->name);
1999  }
2000  /*
2001  BOOST_FOREACH(EdgeDescriptor oe, boost::out_edges(stateToMove, *stg))
2002  {
2003  vertex next_state = boost::target(oe, *stg);
2004  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "(F)newEdge " + clonedStateInfo->name + "->" +
2005  stg->GetStateInfo(next_state == stateToClone ? clonedState : next_state)->name);
2006  EdgeDescriptor new_edge = HLS->STG->STG_builder->connect_state(clonedState,
2007  next_state == stateToClone ? clonedState : next_state, stg->GetSelector(oe));
2008  HLS->STG->STG_builder->copy_condition(new_edge, oe);
2009  if(next_state != stateToClone)
2010  {
2011  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level,
2012  "all path for " + stg->GetStateInfo(next_state)->name + "set to true");
2013  stg->GetStateInfo(next_state)->all_paths = true;
2014  }
2015  }
2016  */
2018  }
2019  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Moved with duplication");
2020  return;
2021 }
#define TYPE_SWITCH
constant identifying the node type of a SWITCH operation.
Definition: op_graph.hpp:105
void Initialize() override
Initialize the step (i.e., like a constructor, but executed just before exec.
#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
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
boost::graph_traits< graph >::out_edge_iterator OutEdgeIterator
out_edge_iterator definition.
Definition: graph.hpp:1312
#define GET_TYPE(data, vertex_index)
Helper macro returning the type associated with a node.
Basic block control flow graph.
File containing functions and utilities to support the printing of debug messagges.
refcount< StateTransitionGraphManager > StateTransitionGraphManagerRef
refcount definition to allocate the class
#define PRINT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
const StateTransitionGraph_constructorRef STG_builder
reference to the class for building the graph
#define DEBUG_LEVEL_PEDANTIC
very verbose debugging print is performed.
This file contains the structures needed to manage a graph that will represent the state transition g...
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
string target
Definition: lenet_tvm.py:16
#define GET_CLASS(obj)
Macro returning the actual type of an object.
void move_without_duplication(const vertex stateToMove, const vertex secondLastState, const vertex destinationState, const std::map< vertex, std::list< vertex >> &global_starting_ops, const std::map< vertex, std::list< vertex >> &global_executing_ops, const std::map< vertex, std::list< vertex >> &global_ending_ops, const CustomOrderedSet< unsigned int > &defSet, const CustomOrderedSet< unsigned int > &useSet)
Copies all the operations of the state to move in the following.
Generic class managing all the stg creation algorithms.
Definition: STG_creator.hpp:55
#define TYPE_IF
constant identifying the node type of an IF operation.
Definition: op_graph.hpp:100
const StateTransitionGraphConstRef CGetEPPStg() const
Returns pointer to acyclic STG with additional edges for Efficient Path Profiling.
const int output_level
The output level.
void move_with_duplication(const vertex stateToMove, const vertex secondLastState, const vertex stateToClone, const std::map< vertex, std::list< vertex >> &global_starting_ops, const std::map< vertex, std::list< vertex >> &global_executing_ops, const std::map< vertex, std::list< vertex >> &global_ending_ops, const CustomOrderedSet< unsigned int > &defSet, const CustomOrderedSet< unsigned int > &useSet)
Duplicates the first state of the destination bb and copies all the operations of the state to move i...
vertex get_entry_state() const
Gets vertex that represents state that contains entry node.
RelationshipType
The relationship type.
DesignFlowStep_Status InternalExec() override
Execute the step.
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
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
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)
#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
AbsControlStep get_cstep_end(const vertex &op) const
Return the last clock cycle in which the operation execute.
Definition: schedule.cpp:302
void ComputeCyclesCount(bool is_pipelined)
Compute minimum and maximum number of cycles for bounded scheduling.
AllocationInformationRef allocation_information
Store the technology information.
Definition: hls.hpp:115
vertex get_exit_state() const
Gets vertex that represents state that contains exit node.
Collect information about resource performance.
#define min(x, y)
Class specification of the manager of the technology library data structures.
Class used to manage a graph into finite state machine representation; it contains methods to build t...
static technology_nodeRef get_fu(const std::string &fu_name, const HLS_managerConstRef hls_manager)
Returns the technology_node associated with the given operation.
Data structure describing a basic block at tree level.
#define INTERFACE_LIBRARY
interface library
#define OUTPUT_LEVEL_MINIMUM
minimum debugging print is performed.
redefinition of map to manage ordered/unordered structures
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
StateTransitionGraphRef GetEPPStg()
Returns pointer to acyclic STG with additional edges for Efficient Path Profiling.
#define TYPE_PHI
constant string identifying an operation node of type PHI
Definition: op_graph.hpp:135
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
#define FB_CFG_SELECTOR
Feedback control flow edge selector.
#define max
Definition: backprop.h:17
bool registered_inputs
true when the module has registered inputs
Definition: hls.hpp:147
const OpNodeInfoConstRef CGetOpNodeInfo(const vertex node) const
Returns the info associated with a node.
Definition: op_graph.hpp:843
#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
fu_bindingRef Rfu
Store the refcounted functional unit binding of the operations.
Definition: hls.hpp:121
const CustomUnorderedSet< std::tuple< HLSFlowStep_Type, HLSFlowStepSpecializationConstRef, HLSFlowStep_Relationship > > ComputeHLSRelationships(const DesignFlowStep::RelationshipType relationship_type) const override
Return the set of analyses in relationship with this design step.
int delay(int ritardo)
Definition: delay.c:1
ScheduleRef Rsch
Store the refcounted scheduling of the operations.
Definition: hls.hpp:118
OpVertexSchedSorter(const ScheduleConstRef _sch)
Constructor.
unsigned edges[4545]
Definition: graph.h:25
bool is_instantaneous_operation(vertex operation)
returns true if the operation takes no time
#define TYPE_GOTO
A vertex is of type TYPE_GOTO when it is associated with a goto expression.
Definition: op_graph.hpp:157
This class specifies the characteristic of a particular operation working on a given functional unit...
unsigned map[NUM_VERTICES]
Definition: bfs.c:12
absl::flat_hash_map< T, U, Hash, Eq, Alloc > CustomUnorderedMap
Definition: custom_map.hpp:148
Data structure used to store the schedule of the operations.
Control flow graph.
File contanining the structures necessary to manage a graph that will represent a state transition gr...
HLSFlowStep_Type
Definition: hls_step.hpp:95
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
vertex check_data_dependency(vertex operation, vertex state, std::map< vertex, std::list< vertex >> &global_starting_ops, std::map< vertex, std::list< vertex >> &global_executing_ops)
This method takes as parameters an operation and a state of the STG graph, and returns the operation ...
#define default_COND
constant used to represent label "default" of a switch construct
Basic block control flow graph with feedback.
redefinition of set to manage ordered/unordered structures
#define STOP_TIME(time_var)
Macro used to store the elapsed time into time_var.
Definition: cpu_time.hpp:136
Datastructure to describe functions allocation in high-level synthesis.
const ScheduleConstRef sch
reference to the scheduling
#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
#define T_COND
constant used to represent control edges representing a true edge of a conditional statement...
This file contains the structures needed to manage a graph that will represent the state transition g...
static std::string GetFUName(const std::string &fname, const HLS_managerRef HLSMgr)
Return FU used to implement given function.
Definition: functions.cpp:118
#define TYPE_RW
Constant identifying if a TYPE_EXTERNAL write or read memory.
Definition: op_graph.hpp:217
boost::graph_traits< graph >::vertex_iterator VertexIterator
vertex_iterator definition.
Definition: graph.hpp:1307
static std::string NormalizeTypename(const std::string &id)
Return normalized name of types and variables.
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.
Call graph hierarchy.
#define VIEW_CONVERT_EXPR
constant string identifying view convert expressions
Definition: op_graph.hpp:355
bool can_be_moved(std::list< vertex > &lastStateEndingOp, std::list< vertex > &lastStateConditionalOpList, vertex firstStateNextBb, std::map< vertex, std::list< vertex >> &global_starting_ops, std::map< vertex, std::list< vertex >> &global_executing_ops)
Returns true if all the operations in the list can be moved to the state specified.
bool res_const_operation(vertex &operation, std::list< vertex > &lastStateExecutingOpList, vertex lastSt)
returns true if the number of fu available prevents us from moving that operation in the next state ...
Data structure definition for HLS constraints.
bool operator()(const vertex x, const vertex y) const
Compare scheduling of two vertices.
This file collects some utility functions.
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
void Initialize() override
Initialize the step (i.e., like a constructor, but executed just before exec.
bool registered_done_port
true when the done port is registered
Definition: hls.hpp:149
#define OUTPUT_LEVEL_PEDANTIC
verbose debugging print is performed.
static size_t compute_edge_increments(const StateTransitionGraphManagerRef &STG)
void optimize_cycles(vertex bbEndingCycle, CustomUnorderedMap< vertex, vertex > &first_state, CustomUnorderedMap< vertex, vertex > &last_state, std::map< vertex, std::list< vertex >> &global_starting_ops, std::map< vertex, std::list< vertex >> &global_ending_ops, std::map< vertex, std::list< vertex >> &global_executing_ops, std::map< vertex, std::list< vertex >> &global_onfly_ops)
Given two bb linked by a forwarding edge, this method tries to move overlap the execution of the last...
#define ASSIGN
constant string identifying the operation performed by an assignment.
Definition: op_graph.hpp:224
Data structure used to store the functional-unit binding of the vertexes.
#define WORK_LIBRARY
working library.
BB_based_stg(const ParameterConstRef _parameters, const HLS_managerRef HLSMgr, unsigned int funId, const DesignFlowManagerConstRef design_flow_manager)
Constructor.
#define INFINITE_UINT
UNSIGNED INT representing infinite.
Definition: utility.hpp:70
Class specification of the basic_block structure.
hlsRef HLS
HLS data structure of the function to be analyzed.
static void add_EPP_edges(const StateTransitionGraphManagerRef &STG)
interface of a loop
Data structures used in operations graph.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
unsigned int get_number_fu(unsigned int fu_name) const
Returns the number of functional unit given its id.
interface of loops finding algorithm
void compute_EPP_edge_increments(const std::map< vertex, std::list< vertex >> &starting_ops) const
If hardware discrepancy analysis is activated, use this function to compute the edge increments for t...
this class is used to manage the command-line or XML options.
#define F_COND
constant used to represent control edges representing a false edge of a conditional statement...
StateTransitionGraphRef GetStg()
Returns pointer to state transition graph created.
Wrapper to call graph.
Class implementation of the structural_manager.
StateTransitionGraphManagerRef STG
Store the refcounted state transition graph.
Definition: hls.hpp:124
x
Return the smallest n such that 2^n >= _x.
void compute_use_def(const std::list< vertex > &opEndingList, const std::list< vertex > &opRuningList, const std::list< vertex > &ignoreList, CustomOrderedSet< unsigned int > &useSet, CustomOrderedSet< unsigned int > &defSet, const OpGraphConstRef data)
computes the variables used and defined in the by the given list of operations, and saves them in the...
int debug_level
The debug level.
#define OUTPUT_LEVEL_VERBOSE
verbose debugging print is performed.
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
Datastructure to describe functions allocation in high-level synthesis.
#define NOP_EXPR
constant string identifying some conversion expressions
Definition: op_graph.hpp:335
#define DEBUG_LEVEL_VERBOSE
verbose debugging print is performed.
#define CFG_SELECTOR
Control flow graph edge selector.
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 StateTransitionGraphConstRef CGetStg() const
Returns pointer to state transition graph created.
Datastructure to represent memory information in high-level synthesis.
void add_multi_unbounded_obj(vertex s, const CustomOrderedSet< vertex > &ops)
Class specification of the manager of the tree structures extracted from the raw file.
A brief description of the C++ Header File.
double EstimateControllerDelay() const
estimate the delay of the controller in straightforward mode
#define CONVERT_EXPR
constant string identifying some conversion expressions
Definition: op_graph.hpp:350
std::string get_state_name(vertex state) const
Get the name of a state.
size_t call_sites_number
The number of call points to this function.
Definition: hls.hpp:152
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