PandA-2024.02
schedule.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 "schedule.hpp"
46 
47 #include <filesystem>
48 #include <ostream>
49 
50 #include "behavioral_helper.hpp"
52 #include "fu_binding.hpp"
53 #include "function_behavior.hpp"
54 #include "op_graph.hpp"
55 
56 #include "Parameter.hpp"
57 
60 
62 #include "hls.hpp"
63 #include "hls_constraints.hpp"
64 #include "hls_device.hpp"
65 #include "hls_manager.hpp"
66 
69 
72 
74 #include <set>
75 
77 #include "technology_manager.hpp"
78 
80 #include "dbgPrintHelper.hpp" // for DEBUG_LEVEL_
81 #include "ext_tree_node.hpp"
82 #include "string_manipulation.hpp" // for GET_CLASS
83 #include "tree_basic_block.hpp"
84 #include "tree_helper.hpp"
85 #include "tree_manager.hpp"
86 #include "tree_manipulation.hpp"
87 #include "tree_node.hpp"
88 #include "tree_reindex.hpp"
89 
90 AbsControlStep::AbsControlStep() : std::pair<unsigned int, ControlStep>(0, AbsControlStep::UNKNOWN)
91 {
92 }
93 
94 AbsControlStep::AbsControlStep(const unsigned int basic_block_index, const ControlStep control_step)
95  : std::pair<unsigned int, ControlStep>(basic_block_index, control_step)
96 {
97 }
98 
99 const ControlStep AbsControlStep::UNKNOWN = ControlStep(std::numeric_limits<unsigned int>::max());
100 
102 {
103  if(this->second != other.second)
104  {
105  return this->second < other.second;
106  }
107  return this->first < other.first;
108 }
109 
110 Schedule::Schedule(const HLS_managerConstRef _hls_manager, const unsigned int _function_index,
111  const OpGraphConstRef _op_graph, const ParameterConstRef _parameters)
112  : hls_manager(_hls_manager),
113  TM(_hls_manager->get_tree_manager()),
114  tree_man(new tree_manipulation(TM, _parameters, application_managerRef())),
115  allocation_information(_hls_manager->get_HLS(_function_index)->allocation_information),
116  function_index(_function_index),
117  tot_csteps(0),
118  op_graph(_op_graph),
119  parameters(_parameters),
120  debug_level(_parameters->get_class_debug_level(GET_CLASS(*this)))
121 {
122 }
123 
124 Schedule::~Schedule() = default;
125 
127 {
128  const OpGraphConstRef g = op_graph;
129  std::map<AbsControlStep, OpVertexSet> csteps_partitions;
130  VertexIterator sch_i, sch_end;
131  for(boost::tie(sch_i, sch_end) = boost::vertices(*g); sch_i != sch_end; sch_i++)
132  {
133  const auto control_step = get_cstep(*sch_i);
134  if(csteps_partitions.find(control_step) == csteps_partitions.end())
135  {
136  csteps_partitions.insert(std::make_pair(control_step, OpVertexSet(g)));
137  }
138  auto& control_step_ops = csteps_partitions.at(control_step);
139  control_step_ops.insert(*sch_i);
140  }
141  for(const auto& control_step : csteps_partitions)
142  {
143  for(const auto op : control_step.second)
144  {
145  INDENT_OUT_MEX(0, 0,
146  "---Operation " + GET_NAME(g, op) + "(" + g->CGetOpNodeInfo(op)->GetOperation() + ")" +
147  " scheduled at control step (" + STR(get_cstep(op).second) + "-" +
148  STR(get_cstep_end(op).second) + ") " +
149  (Rfu ? ("on functional unit " + Rfu->get_fu_name(op)) : ""));
150  }
151  }
152 }
153 
155 {
156  private:
160 
161  public:
168  : GraphWriter(op_graph.get(), 0), sch(_sch), opSet(_opSet)
169  {
170  }
171 
175  void operator()(std::ostream& os) const override
176  {
177  os << "//Scheduling solution\n";
178  os << "splines=ortho;\n";
179  std::map<ControlStep, UnorderedSetStdStable<vertex>> inverse_relation;
180  VertexIterator v, v_end;
181  for(boost::tie(v, v_end) = boost::vertices(*printing_graph); v != v_end; v++)
182  {
183  if(!opSet || opSet->find(*v) != opSet->end())
184  {
185  inverse_relation[sch->get_cstep(*v).second].insert(*v);
186  }
187  }
188  for(auto level = ControlStep(0u); level < sch->get_csteps(); ++level)
189  {
190  os << "//Control Step: " << level << std::endl;
191  os << "CS" << level << " [style=plaintext]\n{rank=same; CS" << level << " ";
192  for(const auto operation : inverse_relation[level])
193  {
194  os << boost::get(boost::vertex_index_t(), *printing_graph)[operation] << " ";
195  }
196  os << " ;}\n";
197  }
198  for(auto level = ControlStep(1u); level < sch->get_csteps(); ++level)
199  {
200  os << "CS" << level - 1u << " -> CS" << level << ";\n";
201  }
202  for(auto level = ControlStep(0u); level < sch->get_csteps(); ++level)
203  {
204  if(!inverse_relation[level].empty())
205  {
206  os << "CS" << level << " -> "
207  << boost::get(boost::vertex_index_t(), *printing_graph)[*inverse_relation[level].begin()]
208  << " [style=invis weight=1000 color=dimgrey];\n";
209  }
210  }
211  }
212 };
213 
214 void Schedule::WriteDot(const std::string& file_name, OpGraphConstRef sub_op_graph, OpVertexSet* opSet) const
215 {
216  auto local_op_graph = sub_op_graph ? sub_op_graph : op_graph;
217  const BehavioralHelperConstRef helper = local_op_graph->CGetOpGraphInfo()->BH;
218  std::string output_directory =
219  parameters->getOption<std::string>(OPT_dot_directory) + "/" + helper->get_function_name() + "/";
220  if(!std::filesystem::exists(output_directory))
221  {
222  std::filesystem::create_directories(output_directory);
223  }
224  const VertexWriterConstRef op_label_writer(new OpWriter(local_op_graph.get(), 0));
225  const EdgeWriterConstRef op_edge_property_writer(new OpEdgeWriter(local_op_graph.get()));
226  const GraphWriterConstRef graph_writer(
227  new ScheduleWriter(local_op_graph, ScheduleConstRef(this, null_deleter()), opSet));
228  local_op_graph->InternalWriteDot<const OpWriter, const OpEdgeWriter, const ScheduleWriter>(
229  output_directory + file_name, op_label_writer, op_edge_property_writer, graph_writer);
230 }
231 
232 void Schedule::set_execution(const vertex& op, ControlStep c_step)
233 {
234  const auto operation_index = op_graph->CGetOpNodeInfo(op)->GetNodeId();
235  if(op_starting_cycle.find(operation_index) == op_starting_cycle.end())
236  {
237  op_starting_cycle.emplace(operation_index, c_step);
238  }
239  else
240  {
241  op_starting_cycle.at(operation_index) = c_step;
242  }
243  starting_cycles_to_ops[c_step].insert(operation_index);
244 }
245 
246 void Schedule::set_execution_end(const vertex& op, ControlStep c_step_end)
247 {
248  const auto operation_index = op_graph->CGetOpNodeInfo(op)->GetNodeId();
249  if(op_ending_cycle.find(operation_index) == op_ending_cycle.end())
250  {
251  op_ending_cycle.emplace(operation_index, c_step_end);
252  }
253  else
254  {
255  op_ending_cycle.at(operation_index) = c_step_end;
256  }
257 }
258 
259 bool Schedule::is_scheduled(const vertex& op) const
260 {
261  const auto statement_index = op_graph->CGetOpNodeInfo(op)->GetNodeId();
262  return is_scheduled(statement_index);
263 }
264 
265 bool Schedule::is_scheduled(const unsigned int statement_index) const
266 {
267  return op_starting_cycle.find(statement_index) != op_starting_cycle.end();
268 }
269 
271 {
272  const auto operation_index = op_graph->CGetOpNodeInfo(op)->GetNodeId();
273  THROW_ASSERT(is_scheduled(op), "Operation " + GET_NAME(op_graph, op) + " has not been scheduled");
274  if(operation_index == ENTRY_ID)
275  {
276  return AbsControlStep(BB_ENTRY, op_starting_cycle.at(operation_index));
277  }
278  if(operation_index == EXIT_ID)
279  {
280  return AbsControlStep(BB_EXIT, op_starting_cycle.at(operation_index));
281  }
282  return AbsControlStep(GetPointer<const gimple_node>(TM->CGetTreeNode(operation_index))->bb_index,
283  op_starting_cycle.at(operation_index));
284 }
285 
286 AbsControlStep Schedule::get_cstep(const unsigned int operation_index) const
287 {
288  THROW_ASSERT(op_starting_cycle.find(operation_index) != op_starting_cycle.end(),
289  "Operation " + STR(operation_index) + " has not been scheduled");
290  if(operation_index == ENTRY_ID)
291  {
292  return AbsControlStep(BB_ENTRY, op_starting_cycle.at(operation_index));
293  }
294  if(operation_index == EXIT_ID)
295  {
296  return AbsControlStep(BB_EXIT, op_starting_cycle.at(operation_index));
297  }
298  return AbsControlStep(GetPointer<const gimple_node>(TM->CGetTreeNode(operation_index))->bb_index,
299  op_starting_cycle.at(operation_index));
300 }
301 
303 {
304  const auto statement_index = op_graph->CGetOpNodeInfo(op)->GetNodeId();
305  return get_cstep_end(statement_index);
306 }
307 
308 AbsControlStep Schedule::get_cstep_end(const unsigned int statement_index) const
309 {
310  THROW_ASSERT(is_scheduled(statement_index), "Operation " + STR(statement_index) + " has not been scheduled");
311  THROW_ASSERT(op_ending_cycle.find(statement_index) != op_ending_cycle.end(), "Ending step not stored");
312  if(statement_index == ENTRY_ID)
313  {
314  return AbsControlStep(BB_ENTRY, op_ending_cycle.at(statement_index));
315  }
316  if(statement_index == EXIT_ID)
317  {
318  return AbsControlStep(BB_EXIT, op_ending_cycle.at(statement_index));
319  }
320  return AbsControlStep(GetPointer<const gimple_node>(TM->CGetTreeNode(statement_index))->bb_index,
321  op_ending_cycle.at(statement_index));
322 }
323 
324 unsigned int Schedule::num_scheduled() const
325 {
326  return static_cast<unsigned int>(op_starting_cycle.size());
327 }
328 
330 {
331  tot_csteps = ControlStep(0u);
332  spec.clear();
333  op_starting_cycle.clear();
334  starting_cycles_to_ops.clear();
335 }
336 
337 void Schedule::UpdateTime(const unsigned int operation_index, bool update_cs)
338 {
339  if(operation_index == ENTRY_ID or operation_index == EXIT_ID)
340  {
341  return;
342  }
343 
344  const auto current_starting_time = starting_times[operation_index];
345  const auto current_ending_time = starting_times[operation_index];
346 
348  const auto tn = TM->CGetTreeNode(operation_index);
349  const auto gn = GetPointer<const gimple_node>(tn);
351  "-->Computing ending time of new statement " + STR(gn->index) + ": " + gn->ToString());
352  const auto hls = hls_manager.lock()->get_HLS(function_index);
353  const auto clock_period = hls->HLS_C->get_clock_period() * hls->HLS_C->get_clock_period_resource_fraction();
354  const auto margin = allocation_information->GetClockPeriodMargin();
355  const auto curr_bb_index = gn->bb_index;
356  THROW_ASSERT(curr_bb_index, "Basic block of " + gn->ToString() + " not set");
357  auto starting_time = 0.0;
358 
360  ControlStep starting_cs = ControlStep(0);
361  if(!update_cs)
362  {
363  starting_time = clock_period * from_strongtype_cast<double>(op_starting_cycle.at(operation_index));
364  }
365  if(gn->get_kind() == gimple_assign_K)
366  {
367  tree_helper::compute_ssa_uses_rec_ptr(GetPointer<const gimple_assign>(tn)->op1, rhs_ssa_uses);
368  }
369  else if(gn->get_kind() == gimple_cond_K)
370  {
371  tree_helper::compute_ssa_uses_rec_ptr(GetPointer<const gimple_cond>(tn)->op0, rhs_ssa_uses);
372  }
373  else if(gn->get_kind() == gimple_multi_way_if_K)
374  {
375  const auto gmwi = GetPointer<const gimple_multi_way_if>(tn);
376  for(const auto& cond : gmwi->list_of_cond)
377  {
378  if(cond.first)
379  {
380  tree_helper::compute_ssa_uses_rec_ptr(cond.first, rhs_ssa_uses);
381  }
382  }
383  }
384  else if(gn->get_kind() == gimple_phi_K or gn->get_kind() == gimple_nop_K or gn->get_kind() == gimple_label_K)
385  {
386  }
387  else if(gn->get_kind() == gimple_return_K)
388  {
389  const auto gr = GetPointer<const gimple_return>(tn);
390  if(gr->op)
391  {
392  tree_helper::compute_ssa_uses_rec_ptr(gr->op, rhs_ssa_uses);
393  }
394  }
395  else if(gn->get_kind() == gimple_switch_K)
396  {
397  const auto gs = GetPointer<const gimple_switch>(tn);
398  THROW_ASSERT(gs->op0, " Switch without operand");
399  tree_helper::compute_ssa_uses_rec_ptr(gs->op0, rhs_ssa_uses);
400  }
401  else if(gn->get_kind() == gimple_call_K)
402  {
403  tree_helper::compute_ssa_uses_rec_ptr(tn, rhs_ssa_uses);
404  }
405  else if(gn->get_kind() == gimple_asm_K)
406  {
407  const auto ga = GetPointer<const gimple_asm>(tn);
408  if(ga->in)
409  {
410  tree_helper::compute_ssa_uses_rec_ptr(ga->in, rhs_ssa_uses);
411  }
412  if(ga->clob)
413  {
414  tree_helper::compute_ssa_uses_rec_ptr(ga->clob, rhs_ssa_uses);
415  }
416  }
417  else
418  {
419  THROW_UNREACHABLE("Compute new ending time of " + gn->ToString() + " (" + gn->get_kind_text() + ")");
420  }
421  for(const auto ssa_use : rhs_ssa_uses)
422  {
423  if(ssa_use->virtual_flag)
424  {
425  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Virtual SSAs are not considered");
426  continue;
427  }
428  const auto def = ssa_use->CGetDefStmt();
429  const auto def_gn = GetPointer<const gimple_node>(GET_CONST_NODE(def));
430  if(def_gn->get_kind() == gimple_nop_K)
431  {
433  continue;
434  }
435  if(def_gn->get_kind() == gimple_assign_K and GetPointer<const gimple_assign>(GET_NODE(def))->clobber)
436  {
438  continue;
439  }
440  THROW_ASSERT(def_gn->bb_index,
441  "Basic block of " + def_gn->ToString() + " which defines " + ssa_use->ToString() + " not set");
442  if(def_gn->bb_index != curr_bb_index)
443  {
445  "---Definition " + STR(def->index) + " - " + def->ToString() + " is in BB" +
446  STR(curr_bb_index));
447  continue;
448  }
450  {
451  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Defined by an unbounded statement");
452  continue;
453  }
454  THROW_ASSERT(ending_times.find(def_gn->index) != ending_times.end(), "Not possible because ending time of " +
455  def_gn->ToString() + " (which defines " +
456  ssa_use->ToString() + ") is unknown");
458  "---Definition " + STR(def->index) + " - " + def->ToString() + " ends at " +
459  STR(ending_times.at(def_gn->index)));
460 
462  if(get_cstep_end(def_gn->index).second > starting_cs)
463  {
464  starting_cs = get_cstep_end(def_gn->index).second;
465  }
466 
468  const auto ending_time = ending_times.at(def_gn->index);
469  const auto connection_time = allocation_information->GetConnectionTime(
470  def_gn->index, operation_index, AbsControlStep(gn->bb_index, AbsControlStep::UNKNOWN));
471  if(ending_time + connection_time >= starting_time)
472  {
473  starting_time = ending_time + connection_time;
474  }
475  }
476  starting_times[operation_index] = starting_time;
477  const auto cycles = allocation_information->GetCycleLatency(gn->index);
478  if(cycles > 1)
479  {
481  const auto first_stage_latency =
483  0.0 :
485  auto first_stage_ending = starting_time + first_stage_latency;
486  if(first_stage_ending != 0.0 and
487  (floor((first_stage_ending + margin) / clock_period) != floor((starting_time) / clock_period)))
488  {
489  first_stage_ending = ((ceil((first_stage_ending + margin) / clock_period) + 1) * clock_period);
490  }
491  else
492  {
493  first_stage_ending = ((ceil((first_stage_ending + margin) / clock_period) * clock_period));
494  }
495  const auto other_cycles_latency =
496  (cycles - 2) * clock_period +
497  allocation_information->GetTimeLatency(gn->index, fu_binding::UNKNOWN, cycles - 1).second;
498  ending_times[operation_index] = first_stage_ending + other_cycles_latency;
499  }
500  else
501  {
502  const auto latency = allocation_information->GetTimeLatency(gn->index, fu_binding::UNKNOWN).first;
503  ending_times[operation_index] = starting_time + latency;
505  if(floor((ending_times[operation_index] +
506  allocation_information->GetConnectionTime(operation_index, 0,
508  margin) /
509  clock_period) != floor(starting_times[operation_index] / clock_period))
510  {
511  starting_times[operation_index] = ceil(starting_times[operation_index] / clock_period) * clock_period;
512  ending_times[operation_index] = starting_times[operation_index] + latency;
514  "---Fixed ending time is " + STR(ending_times[operation_index]));
515  }
516  }
517 
519  const bool updated_time = starting_times[operation_index] != current_starting_time or
520  starting_times[operation_index] != current_ending_time;
521  if(updated_time)
522  {
524  "---Execution time updated from [" + STR(current_starting_time) + "---" +
525  STR(current_ending_time) + "] to [" + STR(starting_times[operation_index]) + "---" +
526  STR(ending_times[operation_index]) + "]");
527  }
528 
529  if(update_cs)
530  {
532  if(is_scheduled(operation_index))
533  {
534  starting_cycles_to_ops[op_starting_cycle.at(operation_index)].erase(operation_index);
535  }
536  auto valS = ControlStep(static_cast<unsigned int>(floor(starting_times[operation_index] / clock_period)));
537  if(op_starting_cycle.find(operation_index) == op_starting_cycle.end())
538  {
539  op_starting_cycle.emplace(operation_index, valS);
540  }
541  else
542  {
543  op_starting_cycle.at(operation_index) = valS;
544  }
545  auto valE = ControlStep(static_cast<unsigned int>(floor(ending_times[operation_index] / clock_period)));
546  if(op_ending_cycle.find(operation_index) == op_ending_cycle.end())
547  {
548  op_ending_cycle.emplace(operation_index, valE);
549  }
550  else
551  {
552  op_ending_cycle.at(operation_index) = valE;
553  }
554  }
555  if(allocation_information->IsVariableExecutionTime(operation_index) and updated_time)
556  {
558  "-->Checking if simultaneous operations have to be rescheduled");
559  const auto reschedule = [&]() -> bool {
560  if(not is_scheduled(operation_index))
561  {
562  return false;
563  }
564  for(const auto simultaneous_operation : starting_cycles_to_ops[op_starting_cycle.at(operation_index)])
565  {
566  if(allocation_information->IsVariableExecutionTime(simultaneous_operation))
567  {
568  return true;
569  }
570  }
571  return false;
572  }();
575  if(reschedule)
576  {
577  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Operations have to be rescheduled");
578  const auto current_cs = op_starting_cycle.at(operation_index);
579  const auto fd = GetPointer<const function_decl>(TM->CGetTreeNode(function_index));
580  const auto sl = GetPointer<const statement_list>(GET_NODE(fd->body));
581  for(const auto& stmt : sl->list_of_bloc.at(gn->bb_index)->CGetStmtList())
582  {
583  if(op_starting_cycle.at(stmt->index) >= current_cs and stmt->index != operation_index and
584  starting_times.find(stmt->index) != starting_times.end())
585  {
586  UpdateTime(stmt->index, true);
587  }
588  }
589  }
591  "<--Checked if simultaneous operations have to be rescheduled");
592  }
594  starting_cycles_to_ops[op_starting_cycle.at(operation_index)].insert(operation_index);
596  "<--Scheduling is " + STR(starting_times.at(operation_index)) + "-" +
597  STR(ending_times.at(operation_index)) + " Control steps: " +
598  STR(op_starting_cycle.at(operation_index)) + "-" + STR(op_ending_cycle.at(operation_index)));
599 }
600 
601 FunctionFrontendFlowStep_Movable Schedule::CanBeMoved(const unsigned int statement_index,
602  const unsigned int basic_block_index) const
603 {
604  THROW_ASSERT(basic_block_index,
605  "Trying to move " + TM->get_tree_node_const(statement_index)->ToString() + " to BB0");
606  const auto hls = hls_manager.lock()->get_HLS(function_index);
607  const FunctionBehaviorConstRef FB = hls_manager.lock()->CGetFunctionBehavior(hls->functionId);
608  const auto behavioral_helper = FB->CGetBehavioralHelper();
609  if(not behavioral_helper->CanBeMoved(statement_index))
610  {
612  "<--No because it is artifical and cannot be moved by default");
614  }
615  const auto clock_period = hls->HLS_C->get_clock_period() * hls->HLS_C->get_clock_period_resource_fraction();
616  const auto clock_period_margin = allocation_information->GetClockPeriodMargin();
617  double bb_ending_time = GetBBEndingTime(basic_block_index);
618  auto current_cs = ControlStep(static_cast<unsigned int>(floor(bb_ending_time / clock_period)));
619  const auto ga = GetPointer<const gimple_assign>(TM->get_tree_node_const(statement_index));
620  THROW_ASSERT(ga, "Asking if " + TM->get_tree_node_const(statement_index)->ToString() + " can be moved");
621  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Checking if " + ga->ToString() + " can be moved");
622  if(behavioral_helper->IsLoad(statement_index))
623  {
624  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--No because it is a load");
626  }
627 
628  const bool unbounded_operation = not allocation_information->is_operation_bounded(statement_index);
629  if(unbounded_operation)
630  {
631  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--No because it is unbounded");
633  }
634  const auto cycles = allocation_information->GetCycleLatency(ga->index);
635  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Cycles: " + STR(cycles));
636  if(cycles > 1)
637  {
638  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--No because it is multicycle");
640  }
641  const auto latency = allocation_information->GetTimeLatency(ga->index, fu_binding::UNKNOWN).first;
642  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Latency: " + STR(latency));
643 
644  double new_ending_time = 0.0;
646  tree_helper::compute_ssa_uses_rec_ptr(ga->op1, rhs_ssa_uses);
647  for(const auto ssa_use : rhs_ssa_uses)
648  {
650  "---Considering used ssa " + STR(ssa_use->index) + " - " + ssa_use->ToString());
651  const auto def = GET_NODE(ssa_use->CGetDefStmt());
652  const auto gn = GetPointer<const gimple_node>(def);
653  if(gn->bb_index != basic_block_index)
654  {
657  "---Defined in a different basic block from the current (BB" + STR(gn->bb_index) + " BB" +
658  STR(basic_block_index) + ")");
659  continue;
660  }
661  THROW_ASSERT(ending_times.find(gn->index) != ending_times.end(),
662  "Ending time of " + gn->ToString() + " is not available");
664  "---Definition " + STR(def->index) + " - " + def->ToString() + " ends at " +
665  STR(ending_times.at(gn->index)));
667  {
668  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Defined by an unbounded statement");
669  continue;
670  }
672  const auto ending_time = ending_times.at(gn->index) +
673  allocation_information->GetConnectionTime(gn->index, statement_index,
674  AbsControlStep(basic_block_index, current_cs));
676  "---Ending time + connection delay of predecessor is " + STR(ending_time));
677  const auto operation_margin =
678  (ceil(ending_time / clock_period) * clock_period) - ending_time - clock_period_margin;
680  "---Connection time to phi is " +
681  STR(allocation_information->GetConnectionTime(statement_index, 0,
682  AbsControlStep(basic_block_index, current_cs))));
683  if(operation_margin > latency + allocation_information->GetConnectionTime(
684  statement_index, 0, AbsControlStep(basic_block_index, current_cs)))
685  {
686  if(ending_time + latency > new_ending_time)
687  {
688  new_ending_time = ending_time + latency;
689  }
690  continue;
691  }
693  "---Ending time of this operation: " + STR((ceil(ending_time / clock_period) * clock_period)) +
694  " + " + STR(latency) + " + " + STR(clock_period) + " = " +
695  STR((ceil(ending_time / clock_period) * clock_period) + latency + clock_period_margin));
697  if(((ceil(ending_time / clock_period) * clock_period) + latency + clock_period_margin) > new_ending_time)
698  {
699  new_ending_time = ((ceil(ending_time / clock_period) * clock_period) + latency);
700  }
702  if(ceil(bb_ending_time / clock_period) * clock_period < (ceil(new_ending_time / clock_period) * clock_period))
703  {
705  "<--No because it can increase the latency of a previus BB: " + STR(bb_ending_time) + " vs. " +
706  STR(new_ending_time));
708  }
709  }
711  "<--Yes because of chaining - New ending time is " + STR(new_ending_time));
713 }
714 
715 #if 0
716 bool Schedule::CanBeChained(const vertex first_statement, const vertex second_statement) const
717 {
718  const auto first_statement_index = op_graph->CGetOpNodeInfo(first_statement)->GetNodeId();
719  const auto second_statement_index = op_graph->CGetOpNodeInfo(second_statement)->GetNodeId();
720  const auto ret = CanBeChained(first_statement_index, second_statement_index);
721  return ret;
722 }
723 
724 bool Schedule::CanBeChained(const unsigned int first_statement_index, const unsigned int second_statement_index) const
725 {
726  if(first_statement_index == ENTRY_ID or first_statement_index == EXIT_ID or second_statement_index == ENTRY_ID or second_statement_index == EXIT_ID)
727  {
728  return true;
729  }
730  const auto first_tree_node = TM->CGetTreeNode(first_statement_index);
731  const auto second_tree_node = TM->CGetTreeNode(second_statement_index);
732  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Checking if (" + STR(second_statement_index) + ") " + STR(second_tree_node) + " can be chained with (" + STR(first_statement_index) + ") " + STR(first_tree_node));
733  const auto first_operation = GetPointer<const gimple_node>(first_tree_node)->operation;
734  const auto second_operation = GetPointer<const gimple_node>(second_tree_node)->operation;
735  const auto hls = hls_manager.lock()->get_HLS(function_index);
736  const auto behavioral_helper = hls->FB->CGetBehavioralHelper();
737  if(behavioral_helper->IsStore(first_statement_index))
738  {
739  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--No because first is a store");
740  return false;
741  }
742  else if(not allocation_information->is_operation_bounded(first_statement_index, allocation_information->GetFuType(first_statement_index)))
743  {
744  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--No because first is unbounded");
745  return false;
746  }
748  else if((behavioral_helper->IsLoad(second_statement_index) or behavioral_helper->IsStore(second_statement_index)) and allocation_information->is_one_cycle_direct_access_memory_unit(allocation_information->GetFuType(second_statement_index)))
749  {
750  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--No because second is a load from distributed memory");
751  return false;
752  }
754  else if ((first_tree_node->get_kind() == gimple_cond_K or first_tree_node->get_kind() == gimple_multi_way_if_K) and behavioral_helper->IsStore(second_statement_index))
755  {
756  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--No because stores cannot be executed in the same clock cycle of the condition which controls it");
757  return false;
758  }
760  else if ((first_tree_node->get_kind() == gimple_cond_K or first_tree_node->get_kind() == gimple_multi_way_if_K) and not allocation_information->is_operation_bounded(second_statement_index, allocation_information->GetFuType(second_statement_index)))
761  {
762  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--No because unbounded operations cannot be executed in the same clock cycle of the condition which controls it");
763  return false;
764  }
766  else if ((first_tree_node->get_kind() == gimple_cond_K or first_tree_node->get_kind() == gimple_multi_way_if_K) and (second_tree_node->get_kind() == gimple_label_K))
767  {
768  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--No because labels and nops cannot be executed in the same clock cycle of the condition which controls it");
769  return false;
770  }
772  else if ((first_tree_node->get_kind() == gimple_cond_K or first_tree_node->get_kind() == gimple_multi_way_if_K) and (GetPointer<const gimple_node>(second_tree_node)->vdef))
773  {
774  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--No because operations with side effect cannot be executed in the same clock cycle of the condition which controls it");
775  return false;
776  }
778  /*else if((((GET_TYPE(op_graph, other) & (TYPE_STORE | TYPE_LOAD)) != 0) and not allocation_information->is_direct_access_memory_unit(allocation_information->GetFuType(other))) and ((GET_TYPE(op_graph, current) & (TYPE_IF | TYPE_MULTIIF)) != 0))
779  {
780  constraint_to_be_added = true;
781  }*/
783  return true;
784 }
785 #endif
786 
787 bool Schedule::EvaluateCondsMerging(const unsigned statement_index, const unsigned int first_condition,
788  const unsigned second_condition, unsigned int function_decl_nid) const
789 {
790  if(not first_condition or not second_condition)
791  {
792  return true;
793  }
794  if(TM->CGetTreeNode(first_condition)->get_kind() == integer_cst_K or
795  TM->CGetTreeNode(second_condition)->get_kind() == integer_cst_K)
796  {
797  return true;
798  }
799  const auto statement = GetPointer<const gimple_node>(TM->get_tree_node_const(statement_index));
800  const auto or_result = tree_man->CreateOrExpr(TM->GetTreeReindex(first_condition),
801  TM->GetTreeReindex(second_condition), blocRef(), function_decl_nid);
802  const auto or_ending_time =
803  std::max(GetReadyTime(first_condition, statement->bb_index),
804  GetReadyTime(second_condition, statement->bb_index)) +
806  ->GetTimeLatency(GetPointer<const ssa_name>(GET_NODE(or_result))->CGetDefStmt()->index, fu_binding::UNKNOWN)
807  .first;
809  "---Checking if merging of conditions can be put at then end BB" + STR(statement->bb_index) +
810  " (ending with " + statement->ToString());
811  return or_ending_time < GetBBEndingTime(statement->bb_index);
812 }
813 
814 bool Schedule::EvaluateMultiWayIfsMerging(const unsigned int first_statement_index,
815  const unsigned int second_statement_index,
816  unsigned int function_decl_nid) const
817 {
818  const auto hls = hls_manager.lock()->get_HLS(function_index);
819  const auto basic_block_graph =
820  hls_manager.lock()->CGetFunctionBehavior(function_index)->CGetBBGraph(FunctionBehavior::FBB);
821  const auto list_of_block =
822  GetPointer<statement_list>(
823  GET_NODE(GetPointer<const function_decl>(TM->get_tree_node_const(function_index))->body))
824  ->list_of_bloc;
825  const auto first_statement = TM->get_tree_node_const(first_statement_index);
826  const auto second_statement = TM->get_tree_node_const(second_statement_index);
827  const auto first_basic_block = GetPointer<const gimple_node>(first_statement)->bb_index;
828  const auto first_block = list_of_block.at(first_basic_block);
829  const auto second_basic_block = GetPointer<const gimple_node>(second_statement)->bb_index;
831  const auto new_ending_time = [=]() -> double {
832  if(first_statement->get_kind() == gimple_cond_K and second_statement->get_kind() == gimple_cond_K)
833  {
834  const auto first_gc = GetPointer<const gimple_cond>(first_statement);
835  const auto first_gc_op = GET_NODE(first_gc->op0);
836  THROW_ASSERT(first_gc_op->get_kind() == ssa_name_K,
837  "Condition of the first gimple cond is " + first_gc_op->ToString());
838  const auto first_gc_input_delay = GetReadyTime(first_gc_op->index, first_gc->bb_index);
839  const auto second_gc = GetPointer<const gimple_cond>(second_statement);
840  const auto second_gc_op = GET_NODE(second_gc->op0);
841  THROW_ASSERT(second_gc_op->get_kind() == ssa_name_K,
842  "Condition of the first gimple cond is " + second_gc_op->ToString());
843  const auto second_gc_input_delay = GetReadyTime(second_gc_op->index, second_gc->bb_index);
844  const auto second_block = list_of_block.at(second_basic_block);
845  if(first_block->true_edge == second_basic_block)
846  {
847  const auto not_operation = tree_man->CreateNotExpr(second_gc->op0, blocRef(), function_decl_nid);
848  const auto not_ending_time =
849  second_gc_input_delay +
850  allocation_information->GetTimeLatency(not_operation->index, fu_binding::UNKNOWN).first;
851  const auto and_operation =
852  tree_man->CreateAndExpr(not_operation, first_gc->op0, blocRef(), function_decl_nid);
853  const auto and_ending_time =
854  std::max(not_ending_time, first_gc_input_delay) +
855  allocation_information->GetTimeLatency(and_operation->index, fu_binding::UNKNOWN).first;
856  return and_ending_time;
857  }
858  else if(first_block->false_edge == second_basic_block)
859  {
860  const auto not_operation = tree_man->CreateNotExpr(first_gc->op0, blocRef(), function_decl_nid);
861  const auto not_ending_time =
862  first_gc_input_delay +
863  allocation_information->GetTimeLatency(not_operation->index, fu_binding::UNKNOWN).first;
864  const auto and_operation =
865  tree_man->CreateAndExpr(second_gc_op, not_operation, blocRef(), function_decl_nid);
866  const auto and_ending_time =
867  std::max(not_ending_time, second_gc_input_delay) +
868  allocation_information->GetTimeLatency(and_operation->index, fu_binding::UNKNOWN).first;
869  return and_ending_time;
870  }
871  else
872  {
873  THROW_UNREACHABLE("BB" + STR(second_basic_block) + " is not on the true edge nor on the false edge of BB" +
874  STR(first_basic_block));
875  }
876  }
877  else if(first_statement->get_kind() == gimple_cond_K and second_statement->get_kind() == gimple_multi_way_if_K)
878  {
879  const auto first_gc = GetPointer<const gimple_cond>(first_statement);
880  const auto second_gmwi = GetPointer<const gimple_multi_way_if>(second_statement);
881  if(first_block->true_edge == second_basic_block)
882  {
883  const auto first_gc_op = GET_NODE(first_gc->op0);
884  THROW_ASSERT(first_gc_op->get_kind() == ssa_name_K,
885  "Condition of the first gimple cond is " + first_gc_op->ToString());
886  const auto first_gc_input_delay = GetReadyTime(first_gc_op->index, first_gc->bb_index);
887  auto current_condition = first_gc_op;
888  auto current_ending_time = first_gc_input_delay;
889  for(const auto& cond : second_gmwi->list_of_cond)
890  {
891  if(cond.first)
892  {
893  const auto not_operation = tree_man->CreateNotExpr(cond.first, blocRef(), function_decl_nid);
894  const auto cond_delay = GetReadyTime(cond.first->index, first_gc->bb_index);
895  const auto not_ending_time =
896  cond_delay +
897  allocation_information->GetTimeLatency(not_operation->index, fu_binding::UNKNOWN).first;
898  const auto and_operation = tree_man->CreateAndExpr(
899  GetPointer<const gimple_assign>(GET_NODE(current_condition))->op0,
900  GetPointer<const gimple_assign>(GET_NODE(not_operation))->op0, blocRef(), function_decl_nid);
901  current_condition = and_operation;
902  current_ending_time =
903  std::max(not_ending_time, current_ending_time) +
904  allocation_information->GetTimeLatency(and_operation->index, fu_binding::UNKNOWN).first;
905  }
906  }
907  return current_ending_time;
908  }
909  else if(first_block->false_edge == second_basic_block)
910  {
911  const auto first_gc_op = GET_NODE(first_gc->op0);
912  THROW_ASSERT(first_gc_op->get_kind() == ssa_name_K,
913  "Condition of the first gimple cond is " + first_gc_op->ToString());
914  auto current_ending_time = 0.0;
915  const auto not_operation = tree_man->CreateNotExpr(first_gc_op, blocRef(), function_decl_nid);
916  const auto not_ending_time =
917  GetReadyTime(first_gc_op->index, first_basic_block) +
918  allocation_information->GetTimeLatency(not_operation->index, fu_binding::UNKNOWN).first;
919  for(const auto& cond : second_gmwi->list_of_cond)
920  {
921  const auto and_operation =
922  tree_man->CreateAndExpr(GetPointer<const gimple_assign>(GET_NODE(not_operation))->op0, cond.first,
923  blocRef(), function_decl_nid);
924  const auto and_ending_time =
925  std::max(not_ending_time, GetReadyTime(cond.first->index, first_basic_block)) +
926  allocation_information->GetTimeLatency(and_operation->index, fu_binding::UNKNOWN).first;
927  current_ending_time = std::max(current_ending_time, and_ending_time);
928  }
929  return current_ending_time;
930  }
931  else
932  {
933  THROW_UNREACHABLE("BB" + STR(second_basic_block) + " is not on the true edge nor on the false edge of BB" +
934  STR(first_basic_block));
935  }
936  }
937  else if(first_statement->get_kind() == gimple_multi_way_if_K and second_statement->get_kind() == gimple_cond_K)
938  {
939  const auto first_gmwi = GetPointer<const gimple_multi_way_if>(first_statement);
940  const auto second_gc = GetPointer<const gimple_cond>(second_statement);
941  const auto second_gc_op = GET_NODE(second_gc->op0);
942 
944  const auto default_basic_block = first_gmwi->list_of_cond.back().second;
945  if(default_basic_block != second_basic_block)
946  {
947  for(const auto& cond : first_gmwi->list_of_cond)
948  {
949  if(cond.second == second_basic_block)
950  {
951  auto const not_operation = tree_man->CreateNotExpr(second_gc_op, blocRef(), function_decl_nid);
952  auto const not_ending_time =
953  GetReadyTime(second_gc_op->index, first_basic_block) +
954  allocation_information->GetTimeLatency(not_operation->index, fu_binding::UNKNOWN).first;
955  const auto and_operation =
956  tree_man->CreateAndExpr(GetPointer<const gimple_assign>(GET_NODE(not_operation))->op0, cond.first,
957  blocRef(), function_decl_nid);
958  const auto and_ending_time =
959  std::max(not_ending_time, GetReadyTime(cond.first->index, first_basic_block)) +
960  allocation_information->GetTimeLatency(and_operation->index, fu_binding::UNKNOWN).first;
961  return and_ending_time;
962  }
963  }
964  THROW_UNREACHABLE("");
965  }
966  else
967  {
968  auto current_condition = tree_nodeRef();
969  auto current_ending_time = 0.0;
970  for(const auto& cond : first_gmwi->list_of_cond)
971  {
972  if(cond.first)
973  {
974  auto const not_operation = tree_man->CreateNotExpr(cond.first, blocRef(), function_decl_nid);
975  const auto not_ending_time =
976  GetReadyTime(cond.first->index, first_basic_block) +
977  allocation_information->GetTimeLatency(not_operation->index, fu_binding::UNKNOWN).first;
978  const auto and_operation =
979  current_condition ?
980  tree_man->CreateAndExpr(current_condition, not_operation, blocRef(), function_decl_nid) :
981  not_operation;
982  const auto and_ending_time =
983  current_condition ?
984  (std::max(not_ending_time, current_ending_time) +
985  allocation_information->GetTimeLatency(and_operation->index, fu_binding::UNKNOWN).first) :
986  not_ending_time;
987  current_condition = and_operation;
988  current_ending_time = and_ending_time;
989  }
990  }
991  const auto and_operation =
992  tree_man->CreateAndExpr(current_condition, second_gc_op, blocRef(), function_decl_nid);
993  const auto and_ending_time =
994  std::max(current_ending_time, GetReadyTime(second_gc_op->index, first_basic_block)) +
995  allocation_information->GetTimeLatency(and_operation->index, fu_binding::UNKNOWN).first;
996  return and_ending_time;
997  }
998  }
999  else if(first_statement->get_kind() == gimple_multi_way_if_K and
1000  second_statement->get_kind() == gimple_multi_way_if_K)
1001  {
1002  const auto first_gmwi = GetPointer<const gimple_multi_way_if>(first_statement);
1003  const auto second_gmwi = GetPointer<const gimple_multi_way_if>(second_statement);
1004 
1005  const auto default_basic_block = first_gmwi->list_of_cond.back().second;
1006  if(default_basic_block != second_basic_block)
1007  {
1008  for(const auto& first_cond : first_gmwi->list_of_cond)
1009  {
1010  if(first_cond.second == second_basic_block)
1011  {
1012  auto current_condition = first_cond.first;
1013  auto current_ending_time = GetReadyTime(first_cond.first->index, first_basic_block);
1014  for(const auto& second_cond : second_gmwi->list_of_cond)
1015  {
1016  if(second_cond.first)
1017  {
1018  const auto not_operation =
1019  tree_man->CreateNotExpr(second_cond.first, blocRef(), function_decl_nid);
1020  const auto cond_delay = GetReadyTime(second_cond.first->index, first_basic_block);
1021  const auto not_ending_time =
1022  cond_delay +
1023  allocation_information->GetTimeLatency(not_operation->index, fu_binding::UNKNOWN).first;
1024  const auto and_operation =
1025  tree_man->CreateAndExpr(GetPointer<const gimple_assign>(GET_NODE(current_condition))->op0,
1026  GetPointer<const gimple_assign>(GET_NODE(not_operation))->op0,
1027  blocRef(), function_decl_nid);
1028  current_condition = and_operation;
1029  current_ending_time =
1030  std::max(not_ending_time, current_ending_time) +
1031  allocation_information->GetTimeLatency(and_operation->index, fu_binding::UNKNOWN).first;
1032  }
1033  }
1034  return current_ending_time;
1035  }
1036  }
1037  THROW_UNREACHABLE("");
1038  }
1039  else
1040  {
1041  auto current_condition = tree_nodeRef();
1042  auto current_ending_time = 0.0;
1043  for(const auto& cond : first_gmwi->list_of_cond)
1044  {
1045  if(cond.first)
1046  {
1047  const auto not_operation = tree_man->CreateNotExpr(cond.first, blocRef(), function_decl_nid);
1048  const auto not_ending_time = GetReadyTime(cond.first->index, first_basic_block);
1049  const auto and_operation =
1050  current_condition ?
1051  tree_man->CreateAndExpr(GetPointer<const gimple_assign>(GET_NODE(current_condition))->op0,
1052  cond.first, blocRef(), function_decl_nid) :
1053  not_operation;
1054  const auto and_ending_time =
1055  current_condition ?
1056  std::max(not_ending_time, current_ending_time) +
1057  allocation_information->GetTimeLatency(and_operation->index, fu_binding::UNKNOWN).first :
1058  not_ending_time;
1059  current_condition = and_operation;
1060  current_ending_time = and_ending_time;
1061  }
1062  }
1063  for(const auto& cond : second_gmwi->list_of_cond)
1064  {
1065  if(cond.first)
1066  {
1067  const auto and_operation =
1068  tree_man->CreateAndExpr(GetPointer<const gimple_assign>(GET_NODE(current_condition))->op0,
1069  cond.first, blocRef(), function_decl_nid);
1070  const auto and_ending_time =
1071  std::max(current_ending_time, GetReadyTime(cond.first->index, first_basic_block)) +
1072  allocation_information->GetTimeLatency(and_operation->index, fu_binding::UNKNOWN).first;
1073  current_ending_time = std::max(and_ending_time, current_ending_time);
1074  }
1075  }
1076  return current_ending_time;
1077  }
1078  }
1079  else
1080  {
1081  THROW_UNREACHABLE("");
1082  return 0.0;
1083  }
1084  THROW_UNREACHABLE("");
1085  return 0.0;
1086  }();
1087  return new_ending_time < GetBBEndingTime(first_basic_block) ? true : false;
1088 }
1089 
1090 double Schedule::GetReadyTime(const unsigned int tree_node_index, const unsigned int basic_block_index) const
1091 {
1092  const auto sn = GetPointer<const ssa_name>(TM->get_tree_node_const(tree_node_index));
1093  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Computing ready time of " + sn->ToString());
1094  const auto def = GetPointer<gimple_node>(GET_NODE(sn->CGetDefStmt()));
1095  if(def->get_kind() == gimple_phi_K)
1096  {
1098  return 0.0;
1099  }
1100  if(def->get_kind() == gimple_assign_K)
1101  {
1102  if(def->bb_index != basic_block_index)
1103  {
1105  return 0.0;
1106  }
1107  THROW_ASSERT(ending_times.find(def->index) != ending_times.end(),
1108  "Ending time of " + def->ToString() + " not found");
1110  return ending_times.at(def->index);
1111  }
1112  THROW_UNREACHABLE("");
1113  return 0.0;
1114 }
1115 
1116 double Schedule::GetBBEndingTime(const unsigned int basic_block_index) const
1117 {
1118  const auto hls = hls_manager.lock()->get_HLS(function_index);
1119  const auto clock_period = hls->HLS_C->get_clock_period() * hls->HLS_C->get_clock_period_resource_fraction();
1120  const auto margin = allocation_information->GetClockPeriodMargin();
1121  const auto tn = TM->get_tree_node_const(function_index);
1122  const auto fd = GetPointer<const function_decl>(tn);
1123  THROW_ASSERT(GetPointer<statement_list>(GET_NODE(fd->body))->list_of_bloc.find(basic_block_index) !=
1124  GetPointer<statement_list>(GET_NODE(fd->body))->list_of_bloc.end(),
1125  "BB" + STR(basic_block_index) + " not found");
1126  const auto block = GetPointer<statement_list>(GET_NODE(fd->body))->list_of_bloc.at(basic_block_index);
1127  const auto stmt_list = block->CGetStmtList();
1128  if(stmt_list.size() == 0)
1129  {
1130  return 0.0;
1131  }
1132  const auto ending_time =
1133  std::max_element(stmt_list.begin(), stmt_list.end(), [=](const tree_nodeRef first, const tree_nodeRef second) {
1134  return ending_times.at(first->index) < ending_times.at(second->index);
1135  });
1136  THROW_ASSERT(ending_time != stmt_list.end(), "");
1137  return ceil((ending_times.at((*ending_time)->index) + margin) / clock_period) * clock_period;
1138 }
1139 
1140 double Schedule::GetEndingTime(const unsigned int operation_index) const
1141 {
1142  if(operation_index == ENTRY_ID or operation_index == EXIT_ID)
1143  {
1144  return 0.0;
1145  }
1146  THROW_ASSERT(ending_times.find(operation_index) != ending_times.end(),
1147  "Ending time of operation " + STR(TM->CGetTreeNode(operation_index)) + " not found");
1148  return ending_times.at(operation_index);
1149 }
1150 
1151 double Schedule::GetStartingTime(const unsigned int operation_index) const
1152 {
1153  if(operation_index == ENTRY_ID or operation_index == EXIT_ID)
1154  {
1155  return 0.0;
1156  }
1157  THROW_ASSERT(starting_times.find(operation_index) != starting_times.end(),
1158  "Starting time of operation " + STR(operation_index) + " not found");
1159  return starting_times.at(operation_index);
1160 }
1161 
1162 double Schedule::get_fo_correction(unsigned int first_operation, unsigned int second_operation) const
1163 {
1164  const auto edge = std::pair<unsigned int, unsigned int>(first_operation, second_operation);
1165  if(connection_times.find(edge) != connection_times.end())
1166  {
1167  return connection_times.at(edge);
1168  }
1169  else
1170  {
1171  return 0.0;
1172  }
1173 }
1174 
1175 const std::string Schedule::PrintTimingInformation(const unsigned int statement_index) const
1176 {
1177  return "[" + NumberToString(GetStartingTime(statement_index), 2, 7) + "---" +
1178  NumberToString(GetEndingTime(statement_index), 2, 7) + "(" +
1179  NumberToString(GetEndingTime(statement_index) - GetStartingTime(statement_index), 2, 7) + ")" + "]";
1180 }
1181 
1182 class StartingTimeSorter : std::binary_function<unsigned int, unsigned int, bool>
1183 {
1184  protected:
1187 
1188  public:
1193  explicit StartingTimeSorter(const CustomMap<unsigned int, double>& _starting_times) : starting_times(_starting_times)
1194  {
1195  }
1196 
1203  bool operator()(const unsigned int x, const unsigned int y) const
1204  {
1205  if(starting_times.at(x) == starting_times.at(y))
1206  {
1207  return x < y;
1208  }
1209  else
1210  {
1211  return starting_times.at(x) < starting_times.at(y);
1212  }
1213  }
1214 };
1215 
1217 {
1218  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Considering operations of state " + state_info->name);
1219 
1221  CustomSet<unsigned int> critical_paths;
1223  double ending_state_time = 0;
1224  for(const auto starting_operation : state_info->starting_operations)
1225  {
1226  const auto node_id = op_graph->CGetOpNodeInfo(starting_operation)->GetNodeId();
1227  if(node_id == ENTRY_ID or node_id == EXIT_ID)
1228  {
1229  continue;
1230  }
1231  const auto stmt = TM->get_tree_node_const(node_id);
1232  if(stmt->get_kind() == gimple_phi_K)
1233  {
1234  continue;
1235  }
1236  const bool found = std::find(state_info->ending_operations.begin(), state_info->ending_operations.end(),
1237  starting_operation) != state_info->ending_operations.end();
1238  const auto ending_time =
1239  found ? ending_times.at(stmt->index) :
1240  starting_times.at(stmt->index) +
1242  0.0 :
1245  "---Ending time of " + stmt->ToString() + " is " + STR(ending_time));
1246  if(ending_time > ending_state_time)
1247  {
1249  "---Updating ending time to " + STR(ending_time) + " because of " + stmt->ToString());
1250  ending_state_time = ending_time;
1251  }
1252  }
1253  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Ending time of state is " + STR(ending_state_time));
1254 
1255  std::set<unsigned int, StartingTimeSorter> to_be_processed =
1256  std::set<unsigned int, StartingTimeSorter>(StartingTimeSorter(starting_times));
1257  for(const auto starting_operation : state_info->starting_operations)
1258  {
1259  const auto node_id = op_graph->CGetOpNodeInfo(starting_operation)->GetNodeId();
1260  if(node_id == ENTRY_ID or node_id == EXIT_ID)
1261  {
1262  continue;
1263  }
1264  const auto stmt = TM->get_tree_node_const(node_id);
1266  "---Stmt " + stmt->ToString() + " ends at " + STR(ending_times.at(stmt->index)));
1267  const bool found = std::find(state_info->ending_operations.begin(), state_info->ending_operations.end(),
1268  starting_operation) != state_info->ending_operations.end();
1269  const auto ending_time =
1270  found ? ending_times.at(stmt->index) :
1271  starting_times.at(stmt->index) +
1273  0.0 :
1275  if(ending_time == ending_state_time)
1276  {
1277  to_be_processed.insert(stmt->index);
1278  critical_paths.insert(stmt->index);
1279  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Adding " + stmt->ToString() + " to critical path");
1280  }
1281  }
1282  while(to_be_processed.size())
1283  {
1284  const auto last = *(to_be_processed.rbegin());
1285  const auto starting_time = starting_times.at(last);
1286  to_be_processed.erase(last);
1287  const auto stmt_tn = TM->get_tree_node_const(last);
1288  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Processing " + stmt_tn->ToString());
1289  const auto gn = GetPointer<const gimple_node>(stmt_tn);
1290  CustomOrderedSet<const ssa_name*> rhs_ssa_uses;
1291  if(gn->get_kind() == gimple_assign_K)
1292  {
1293  tree_helper::compute_ssa_uses_rec_ptr(GetPointer<const gimple_assign>(stmt_tn)->op1, rhs_ssa_uses);
1294  }
1295  else if(gn->get_kind() == gimple_cond_K)
1296  {
1297  tree_helper::compute_ssa_uses_rec_ptr(GetPointer<const gimple_cond>(stmt_tn)->op0, rhs_ssa_uses);
1298  }
1299  else if(gn->get_kind() == gimple_multi_way_if_K)
1300  {
1301  const auto gmwi = GetPointer<const gimple_multi_way_if>(stmt_tn);
1302  for(const auto& cond : gmwi->list_of_cond)
1303  {
1304  if(cond.first)
1305  {
1306  tree_helper::compute_ssa_uses_rec_ptr(cond.first, rhs_ssa_uses);
1307  }
1308  }
1309  }
1310  else if(gn->get_kind() == gimple_phi_K or gn->get_kind() == gimple_nop_K or gn->get_kind() == gimple_label_K)
1311  {
1312  }
1313  else if(gn->get_kind() == gimple_return_K)
1314  {
1315  const auto gr = GetPointer<const gimple_return>(stmt_tn);
1316  if(gr->op)
1317  {
1318  tree_helper::compute_ssa_uses_rec_ptr(gr->op, rhs_ssa_uses);
1319  }
1320  }
1321  else if(gn->get_kind() == gimple_switch_K)
1322  {
1323  const auto gs = GetPointer<const gimple_switch>(stmt_tn);
1324  THROW_ASSERT(gs->op0, " Switch without operand");
1325  tree_helper::compute_ssa_uses_rec_ptr(gs->op0, rhs_ssa_uses);
1326  }
1327  else if(gn->get_kind() == gimple_call_K)
1328  {
1329  tree_helper::compute_ssa_uses_rec_ptr(stmt_tn, rhs_ssa_uses);
1330  }
1331  else if(gn->get_kind() == gimple_asm_K)
1332  {
1333  tree_helper::compute_ssa_uses_rec_ptr(stmt_tn, rhs_ssa_uses);
1334  }
1335  else
1336  {
1337  THROW_UNREACHABLE("Computing critical path analyzing " + gn->ToString() + " (" + gn->get_kind_text() + ")");
1338  }
1339  for(const auto ssa_use : rhs_ssa_uses)
1340  {
1341  if(ssa_use->virtual_flag)
1342  {
1343  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Virtual SSAs are not considered");
1344  continue;
1345  }
1346  const auto def = GET_NODE(ssa_use->CGetDefStmt());
1347  const auto def_gn = GetPointer<const gimple_node>(def);
1348  if(def_gn->get_kind() == gimple_nop_K)
1349  {
1351  continue;
1352  }
1353  if(def_gn->get_kind() == gimple_pragma_K)
1354  {
1356  continue;
1357  }
1358  if(GetPointer<const gimple_assign>(def) and GetPointer<const gimple_assign>(def)->clobber)
1359  {
1361  continue;
1362  }
1363  THROW_ASSERT(def_gn->bb_index,
1364  "Basic block of " + def_gn->ToString() + " which defines " + ssa_use->ToString() + " not set");
1365  if(state_info->BB_ids.find(def_gn->bb_index) == state_info->BB_ids.end())
1366  {
1368  "---Definition " + STR(def->index) + " - " + def->ToString() + " is in other state");
1369  continue;
1370  }
1371  THROW_ASSERT(ending_times.find(def_gn->index) != ending_times.end(),
1372  "Not possible because ending time of " + def_gn->ToString() + " (which defines " +
1373  ssa_use->ToString() + ") is unknown");
1375  "---Definition " + STR(def->index) + " - " + def->ToString() + " ends at " +
1376  STR(ending_times.at(def_gn->index)));
1378  const auto ending_time = ending_times.at(def_gn->index);
1379  if(ending_time + allocation_information->GetConnectionTime(
1380  def_gn->index, last,
1381  AbsControlStep(GetPointer<const gimple_node>(stmt_tn)->bb_index,
1382  op_starting_cycle.at(stmt_tn->index))) ==
1383  starting_time)
1384  {
1385  to_be_processed.insert(def_gn->index);
1386  critical_paths.insert(def_gn->index);
1388  "---Adding " + def_gn->ToString() + " to critical path");
1389  }
1390  }
1391  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Processed " + stmt_tn->ToString());
1392  }
1393  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Computed critical path in state " + state_info->name);
1394  return critical_paths;
1395 }
1396 
1398 {
1399  TM = hls_manager.lock()->get_tree_manager();
1400  allocation_information = hls_manager.lock()->get_HLS(function_index)->allocation_information;
1401  tot_csteps = ControlStep(0);
1402  op_starting_cycle.clear();
1403  op_ending_cycle.clear();
1404  starting_times.clear();
1405  ending_times.clear();
1406  spec.clear();
1407  op_slack.clear();
1408  const FunctionBehaviorConstRef FB = hls_manager.lock()->CGetFunctionBehavior(function_index);
1410 }
1411 
1412 void Schedule::AddConnectionTimes(unsigned int first_operation, unsigned int second_operation, const double value)
1413 {
1414  connection_times[std::pair<unsigned int, unsigned int>(first_operation, second_operation)] = value;
1415 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
tree_nodeRef CreateOrExpr(const tree_nodeConstRef &first_condition, const tree_nodeConstRef &second_condition, const blocRef &block, unsigned int function_decl_nid) const
Create an or expression.
AbsControlStep()
Empty constructor.
Definition: schedule.cpp:90
tree_nodeRef CreateNotExpr(const tree_nodeConstRef &condition, const blocRef &block, unsigned int function_decl_nid) const
UTILITY.
OpGraphConstRef op_graph
The operation graph (for scheduling purpose) (cannot be const because of = operator) ...
Definition: schedule.hpp:172
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
CustomUnorderedMapUnstable< unsigned int, ControlStep > op_ending_cycle
map between the operation index and the clock cycle on which the operations ends its execution ...
Definition: schedule.hpp:150
Data structure representing the entire HLS information.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
unsigned int GetCycleLatency(const unsigned int operationID) const
Return the latency of an operation in cycle.
File containing functions and utilities to support the printing of debug messagges.
ScheduleWriter(const OpGraphConstRef op_graph, const ScheduleConstRef _sch, OpVertexSet *_opSet)
Constructor.
Definition: schedule.cpp:167
std::string ToString() const
Print this node as string in gimple format.
#define GET_CLASS(obj)
Macro returning the actual type of an object.
Dest from_strongtype_cast(Source source)
std::string get_function_name() const
Return the name of the function.
#define BB_EXIT
constant identifying the basic block node of type exit
std::map< vertex, double > op_slack
slack map
Definition: schedule.hpp:169
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
Edge writer for operation graph.
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)
double get_fo_correction(unsigned int first_operation, unsigned int second_operation) const
return the fan-out correction for a given edge
Definition: schedule.cpp:1162
unsigned int num_scheduled() const
Returns the number of scheduled operations.
Definition: schedule.cpp:324
#define GET_NAME(data, vertex_index)
Helper macro returning the name associated with a node.
tree_managerRef TM
The tree manager.
Definition: schedule.hpp:128
std::string NumberToString(const T number, const size_t precision, const size_t size)
Function with print number in desired format.
CustomOrderedMap< T, U > CustomMap
Definition: custom_map.hpp:167
ControlStep tot_csteps
total number of control steps
Definition: schedule.hpp:140
AbsControlStep get_cstep_end(const vertex &op) const
Return the last clock cycle in which the operation execute.
Definition: schedule.cpp:302
const ScheduleConstRef sch
The schedule to be printed.
Definition: schedule.cpp:158
static const ControlStep UNKNOWN
Constant used to specify unknown control step.
Definition: schedule.hpp:93
Definition of hash function for EdgeDescriptor.
Definition: graph.hpp:1321
void Initialize()
Initialize the data structure.
Definition: schedule.cpp:1397
double GetClockPeriodMargin() const
Return the margin to be considered when performing scheduling.
Class specification of the manager of the technology library data structures.
This class contains the base representation for a generic frontend flow step which works on a single ...
CustomUnorderedMap< vertex, bool > spec
Map for speculation property of each operation vertex.
Definition: schedule.hpp:166
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.
std::string get_fu_name(vertex const &v) const
Returns the name of the functional unit.
Definition: fu_binding.cpp:256
AllocationInformationConstRef allocation_information
The allocation information.
Definition: schedule.hpp:134
Absolute Control step First field is the basic block Second field is the relative control step...
Definition: schedule.hpp:89
const tree_nodeConstRef CGetTreeNode(const unsigned int i) const
A set of operation vertices.
Definition: op_graph.hpp:654
const std::string PrintTimingInformation(const unsigned int statement_index) const
Print the timing information about an operation.
Definition: schedule.cpp:1175
virtual enum kind get_kind() const =0
Virtual function returning the type of the actual class.
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
#define max
Definition: backprop.h:17
CustomMap< ControlStep, CustomSet< unsigned int > > starting_cycles_to_ops
The reverse of op_starting_cycle.
Definition: schedule.hpp:147
const ParameterConstRef parameters
The set of input parameters.
Definition: schedule.hpp:175
const tree_nodeRef get_tree_node_const(unsigned int i) const
Return the reference to the i-th tree_node Constant version of get_tree_node.
const OpNodeInfoConstRef CGetOpNodeInfo(const vertex node) const
Returns the info associated with a node.
Definition: op_graph.hpp:843
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
void UpdateTime(const unsigned int operation_index, bool update_cs=true)
Compute the starting and the ending time of a statement.
Definition: schedule.cpp:337
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
#define EXIT_ID
constant used to represent tree node index of exit operation
Definition: op_graph.hpp:81
bool IsVariableExecutionTime(const unsigned int operation_index) const
Return true if the variable execution time depends on the scheduling.
This class specifies the characteristic of a particular operation working on a given functional unit...
Functor used to write the content of the property of a graph to a dotty file.
Definition: graph.hpp:1480
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.
tree_manipulationConstRef tree_man
The tree manipulation.
Definition: schedule.hpp:131
static void compute_ssa_uses_rec_ptr(const tree_nodeConstRef &tn, CustomOrderedSet< const ssa_name *> &ssa_uses)
recursively compute the pointers to the ssa_name variables used in a statement
FunctionFrontendFlowStep_Movable CanBeMoved(const unsigned int statement_index, const unsigned int basic_block) const
Check if a statement can be moved at the end of a basic block.
Definition: schedule.cpp:601
CustomMap< std::pair< unsigned int, unsigned int >, double > connection_times
Connection times The key is an operation graph edge.
Definition: schedule.hpp:162
void AddConnectionTimes(unsigned int first_operation, unsigned int second_operation, const double value)
Add fan out correction time.
Definition: schedule.cpp:1412
double GetBBEndingTime(const unsigned int basic_block_index) const
Return the ending time of a basic block (i.e., the ending time of the last ending operation...
Definition: schedule.cpp:1116
const unsigned int index
Represent the index read from the raw file and the index-1 of the vector of tree_node associated to t...
Definition: tree_node.hpp:146
Basic block control flow graph with feedback.
void set_execution_end(const vertex &op, ControlStep c_step_end)
Sets the ending clock cycle for the given operation.
Definition: schedule.cpp:246
#define index(x, y)
Definition: Keccak.c:74
tree_nodeRef GetTreeReindex(const unsigned int i)
Return a tree_reindex wrapping the i-th tree_node.
#define BB_ENTRY
constant identifying the basic block node of type entry
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
const unsigned int function_index
The index of the function.
Definition: schedule.hpp:137
This file contains the structures needed to manage a graph that will represent the state transition g...
bool EvaluateMultiWayIfsMerging(const unsigned int first_statement_index, const unsigned int second_statement_index, unsigned int function_decl_nid) const
Evaluate if two conditional statements can be merged to create a gimple_multi_way_if.
Definition: schedule.cpp:814
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
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.
This package is used by all HLS packages to manage resource constraints and characteristics.
Class defining some useful functions to create tree nodes and to manipulate the tree manager...
static const unsigned int UNKNOWN
The value used to identified unknown functional unit.
Definition: fu_binding.hpp:178
bool EvaluateCondsMerging(const unsigned statement_index, const unsigned int first_condition, const unsigned second_condition, unsigned int function_decl_nid) const
Check if a further condition can be added to gimple multi way if without increasing basic block laten...
Definition: schedule.cpp:787
Data structure definition for HLS constraints.
This struct specifies the block node.
Definition: tree_node.hpp:1820
bool is_operation_bounded(const OpGraphConstRef g, const vertex &op, unsigned int fu_type) const
Checks if the given operation has a bounded execution time or not.
This file collects some utility functions.
bool is_one_cycle_direct_access_memory_unit(unsigned int fu_type) const
return true in case the functional unit is a direct_access memory unit with a single clock latency fo...
null deleter
Definition: refcount.hpp:51
double GetStartingTime(const unsigned int operation) const
Return the starting time of the operation.
Definition: schedule.cpp:1151
void print(fu_bindingRef Rfu=fu_bindingRef()) const
Function that prints the class schedule.
Definition: schedule.cpp:126
bool operator<(const AbsControlStep &other) const
Compare two scheduling step.
Definition: schedule.cpp:101
refcount< T > lock() const
Definition: refcount.hpp:212
FunctionFrontendFlowStep_Movable
Enum class used to specify if a statement can be moved.
refcount< const Schedule > ScheduleConstRef
Definition: schedule.hpp:411
const int debug_level
The debug level.
Definition: schedule.hpp:178
CustomSet< unsigned int > ComputeCriticalPath(const StateInfoConstRef state_info) const
Compute the critical path inside a state.
Definition: schedule.cpp:1216
bool is_scheduled(const vertex &op) const
Returns true if the given operation has been already scheduled, false otherwise.
Definition: schedule.cpp:259
Class specification of the tree_reindex support class.
#define ENTRY_ID
constant used to represent tree node index of entry operation
Definition: op_graph.hpp:79
Collect all structs used to write a graph in the dot format.
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.
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
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
void clear()
Erases the current results.
Definition: schedule.cpp:329
int level
Definition: main.c:98
System dependence + anti-dependence + output dependence graph + flow graph.
Classes specification of the tree_node data structures not present in the gcc.
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...
const Wrefcount< const HLS_manager > hls_manager
The HLS manager.
Definition: schedule.hpp:125
refcount< tree_node > tree_nodeRef
RefCount type definition of the tree_node class structure.
Definition: tree_node.hpp:212
double GetReadyTime(const unsigned int tree_node_index, const unsigned int basic_block_index) const
Get when in a basic block an ssa is ready.
Definition: schedule.cpp:1090
Data structure that contains all information about high level synthesis process.
Definition: hls.hpp:83
const CustomMap< unsigned int, double > & starting_times
The starting time.
Definition: schedule.cpp:1186
x
Return the smallest n such that 2^n >= _x.
const HLS_constraintsRef HLS_C
store the HLS constraints
Definition: hls.hpp:110
StartingTimeSorter(const CustomMap< unsigned int, double > &_starting_times)
The constructor.
Definition: schedule.cpp:1193
const OpVertexSet * opSet
Definition: schedule.cpp:159
double GetEndingTime(const unsigned int operation) const
Return the starting time of the operation.
Definition: schedule.cpp:1140
void operator()(std::ostream &os) const override
Redifinition of operator()
Definition: schedule.cpp:175
Data structure definition for high-level synthesis flow.
Operation cannot be moved because of timing.
void set_execution(const vertex &op, ControlStep c_step)
Sets the starting clock cycle for the given operation.
Definition: schedule.cpp:232
This class creates a layer to add nodes and to manipulate the tree_nodes manager. ...
~Schedule()
Destructor.
tree_nodeRef CreateAndExpr(const tree_nodeConstRef &first_condition, const tree_nodeConstRef &second_condition, const blocRef &block, unsigned int function_decl_nid) const
Create an or expression.
Class specification of the manager of the tree structures extracted from the raw file.
HLS specialization of generic_device.
A brief description of the C++ Header File.
int sl
Definition: adpcm.c:105
unsigned int GetFuType(const unsigned int operation) const
Return the functional unit type used to execute an operation.
CustomUnorderedMapUnstable< unsigned int, ControlStep > op_starting_cycle
map between the operation index and the clock cycle on which the operation starts its execution NOTE:...
Definition: schedule.hpp:144
bool operator()(const unsigned int x, const unsigned int y) const
Compare position of two operations.
Definition: schedule.cpp:1203
Schedule(const HLS_managerConstRef hls_manager, const unsigned int function_index, const OpGraphConstRef op_graph, const ParameterConstRef parameters)
Constructor.
Definition: schedule.cpp:110
#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