86 #include <boost/range/adaptor/reversed.hpp> 98 #include "hierarchical_clustering.hpp" 99 struct spec_hierarchical_clustering :
public hierarchical_clustering<>
105 #define DEFAULT_SMALL_NORMALIZED_RESOURCE_AREA 2.0 106 #define MODULE_BINDING_MUX_MARGIN 1.0 107 #define DSP_MARGIN 1.0 108 #define CLOCK_MARGIN 0.97 109 #define OP_THRESHOLD 1000 111 template <
typename OutputIterator>
115 : m_iter(_iter), c2s(_c2s), sdg(_sdg)
119 template <
typename Vertex,
typename Graph>
122 *m_iter++ = boost::get(boost::vertex_index, g, u);
124 template <
typename Edge,
typename Graph>
127 std::cerr <<
GET_NAME(sdg, c2s[boost::get(boost::vertex_index, g, boost::source(e, g))]) <<
"(" 128 << sdg->CGetOpNodeInfo(c2s[boost::get(boost::vertex_index, g, boost::source(e, g))])->GetOperation()
130 << sdg->CGetOpNodeInfo(c2s[boost::get(boost::vertex_index, g,
boost::target(e, g))])->GetOperation()
132 BOOST_THROW_EXCEPTION(boost::not_a_dag());
140 template <
typename VertexListGraph,
typename OutputIterator,
typename P,
typename T,
typename R>
142 OutputIterator
result,
const boost::bgl_named_params<P, T, R>&
params)
145 boost::depth_first_search(g, params.visitor(TopoVisitor(c2s, sdg, result)));
148 template <
typename VertexListGraph,
typename OutputIterator>
171 bool operator()(
const unsigned int& a,
const unsigned int& b)
const 181 double wd_a = allocation_information->
get_DSPs(a);
182 double wd_b = allocation_information->
get_DSPs(b);
183 double wa_a = allocation_information->
get_area(a);
184 double wa_b = allocation_information->
get_area(b);
185 return ((wm_a > wm_b) || (wm_a == wm_b && wd_a > wd_b) || (wm_a == wm_b && wd_a == wd_b && wa_a > wa_b) ||
186 (wm_a == wm_b && wd_a == wd_b && wa_a == wa_b && a < b));
194 : allocation_information(_allocation_soluton)
206 : clique_covering_algorithm(_clique_covering_algorithm)
226 for(
auto current_v : all_candidate_vertices)
229 "-->Considering operation " +
GET_NAME(data, current_v) +
" " +
231 std::vector<HLS_manager::io_binding_type> vars_read = HLSMgr->get_required_values(HLS->functionId, current_v);
232 size_t n_ports = vars_read.size();
233 con_rel[current_v].resize(n_ports);
234 for(
unsigned int port_index = 0; port_index < n_ports; ++port_index)
237 auto tree_var = std::get<0>(vars_read[port_index]);
242 con_rel[current_v][port_index];
244 for(
const auto state : running_states)
248 con_rel_per_vertex_per_port_index.insert(
253 vertex def_op = HLS->Rliv->get_op_where_defined(tree_var);
255 "Variable is defined in " +
GET_NAME(data, def_op));
259 if(def_op_ending_states.find(state) != def_op_ending_states.end())
261 con_rel_per_vertex_per_port_index.insert(
262 std::make_pair(
no_phi_chained, std::make_pair(tree_var, def_op)));
264 else if(HLS->storage_value_information->is_a_storage_value(state, tree_var))
266 auto storage_value = HLS->storage_value_information->get_storage_value_index(state, tree_var);
267 con_rel_per_vertex_per_port_index.insert(
277 auto storage_value = HLS->storage_value_information->get_storage_value_index(state, tree_var);
278 THROW_ASSERT(HLS->storage_value_information->is_a_storage_value(state, tree_var),
280 con_rel_per_vertex_per_port_index.insert(
281 std::make_pair(
phi, std::make_pair(storage_value, def_op)));
292 template <
bool do_estimation,
bool do_conversion,
typename vertex_type,
class cluster_type>
294 double& tot_mux_area,
const cluster_type& cluster,
unsigned int& total_muxes,
306 bool has_register_done = HLS->
Rreg && HLS->
Rreg->size() != 0;
307 std::vector<CustomUnorderedSet<unsigned int>> regs_in;
308 std::vector<CustomUnorderedSet<unsigned int>> chained_in;
309 std::vector<CustomUnorderedSet<std::pair<unsigned int, unsigned int>>> module_in;
310 std::vector<CustomUnorderedSet<std::pair<unsigned int, unsigned int>>> module_in_reg;
315 unsigned int n_tot_outgoing_edges = 0, n_tot_outgoing_unbound_operations = 0;
317 unsigned int n_tot_shared = 0;
318 unsigned int max_port_index = 0;
319 for(
auto cv : cluster)
324 current_v =
reinterpret_cast<vertex>(cv);
328 current_v = converter.find(cv)->second;
330 max_port_index =
std::max(max_port_index, static_cast<unsigned int>(con_rel.find(current_v)->second.size()));
332 regs_in.resize(max_port_index);
333 chained_in.resize(max_port_index);
334 module_in.resize(max_port_index);
335 module_in_reg.resize(max_port_index);
337 for(
auto cv : cluster)
342 current_v =
reinterpret_cast<vertex>(cv);
346 current_v = converter.find(cv)->second;
348 THROW_ASSERT(con_rel.find(current_v) != con_rel.end(),
"missing vertex from con_rel data structure");
349 for(
unsigned int port_index_actual = 0; port_index_actual < con_rel.find(current_v)->second.size();
352 auto port_index = port_index_actual;
354 con_rel_per_vertex_per_port_index = con_rel.find(current_v)->second[port_index];
357 if(port_index_actual == 0)
366 for(
auto triple : con_rel_per_vertex_per_port_index)
372 auto tree_var = triple.second.first;
373 chained_in[port_index].insert(
379 auto tree_var = triple.second.first;
380 vertex def_op = triple.second.second;
383 module_in[port_index].insert(std::make_pair(fu->
get_assign(def_op), fu->
get_index(def_op)));
387 chained_in[port_index].insert(tree_var);
393 auto storage_value = triple.second.first;
394 vertex def_op = triple.second.second;
395 if(has_register_done)
401 module_in_reg[port_index].insert(std::make_pair(fu->
get_assign(def_op), fu->
get_index(def_op)));
405 regs_in[port_index].insert(storage_value);
411 auto storage_value = triple.second.first;
412 vertex def_op = triple.second.second;
413 if(has_register_done)
419 module_in_reg[port_index].insert(std::make_pair(fu->
get_assign(def_op), fu->
get_index(def_op)));
423 regs_in[port_index].insert(storage_value);
436 if(has_register_done)
438 auto var_written = HLSMgr->get_produced_value(HLS->
functionId, current_v);
442 for(
const auto estate : end)
451 chained_out.insert(estate);
457 for(
const auto& oe : data->CGetOutEdges(current_v))
462 ++n_tot_outgoing_edges;
467 if(module_out.find(std::make_pair(fu->
get_assign(tgt), fu->
get_index(tgt))) != module_out.end())
479 ++n_tot_outgoing_unbound_operations;
490 for(
unsigned int port_index = 0; port_index < max_port_index; ++port_index)
495 "---Chained in ports: " +
STR(chained_in[port_index].size()));
497 "---Module in ports: " +
STR(module_in[port_index].size()));
499 "---Module in reg ports: " +
STR(module_in_reg[port_index].size()));
500 unsigned int current_muxs = 0;
501 current_muxs +=
static_cast<unsigned int>(regs_in[port_index].size());
502 current_muxs +=
static_cast<unsigned int>(chained_in[port_index].size());
503 current_muxs +=
static_cast<unsigned int>(module_in[port_index].size());
504 current_muxs +=
static_cast<unsigned int>(module_in_reg[port_index].size());
507 total_muxes += current_muxs - 1;
517 "---total number of outgoing edges: " +
STR(n_tot_outgoing_edges));
519 "---total number of outgoing unbound operations: " +
STR(n_tot_outgoing_unbound_operations));
521 "---total number of outgoing bound modules: " +
STR(module_out.size()));
523 if(has_register_done)
528 n_shared = n_tot_shared;
537 : slack_time(_slack_time),
538 starting_time(_starting_time),
539 controller_delay(_controller_delay),
543 data(_HLSMgr->CGetFunctionBehavior(_HLS->functionId)->CGetOpGraph(
FunctionBehavior::FDFG)),
544 area_resource(_area_resource),
553 THROW_ASSERT(!candidate_clique.empty(),
"candidate clique cannot be empty");
555 C_vertex min_slack_vertex = *candidate_clique.begin();
557 unsigned int total_muxes;
558 unsigned int n_shared;
559 double mux_area_estimation, mux_time_estimation;
560 estimate_muxes<true, true, C_vertex>(con_rel, mux_prec, mux_time_estimation, mux_area_estimation,
561 candidate_clique, total_muxes, n_shared, converter, HLSMgr, HLS,
564 double max_starting_time = 0.0;
565 for(
auto current_c : candidate_clique)
567 current_v = converter.find(current_c)->second;
568 max_starting_time =
std::max(max_starting_time, starting_time.find(current_v)->second);
570 if(max_starting_time < controller_delay && total_muxes > 0)
572 max_starting_time = controller_delay;
574 auto vert_it_end = candidate_clique.end();
575 for(
auto vert_it = candidate_clique.begin(); vert_it != vert_it_end; ++vert_it)
577 THROW_ASSERT(converter.find(*vert_it) != converter.end(),
"non-existing vertex");
578 current_v = converter.find(*vert_it)->second;
580 slack_time.find(current_v)->second - (max_starting_time - starting_time.find(current_v)->second);
584 if(curr_slack < min_slack)
586 min_slack_vertex = *vert_it;
587 min_slack = curr_slack;
589 else if(curr_slack == min_slack && min_slack_vertex != *vert_it)
592 boost::graph_traits<cc_compatibility_graph>::out_edge_iterator ei, ei_end;
593 boost::tie(ei, ei_end) = boost::out_edges(*vert_it, cg);
594 for(; ei != ei_end; ++ei)
596 if(candidate_clique.find(
boost::target(*ei, cg)) != candidate_clique.end())
598 weight1 += cg[*ei].weight;
602 boost::tie(ei, ei_end) = boost::out_edges(min_slack_vertex, cg);
603 for(; ei != ei_end; ++ei)
605 if(candidate_clique.find(
boost::target(*ei, cg)) != candidate_clique.end())
607 weight2 += cg[*ei].weight;
611 if(weight1 < weight2)
613 min_slack_vertex = *vert_it;
619 if(total_muxes > 0 && min_slack < 0)
621 v = min_slack_vertex;
628 if(total_muxes > 0 &&
629 ((mux_area_estimation + area_resource) >=
630 (static_cast<double>(candidate_clique.size() + (total_muxes <= n_shared ? n_shared : 0)) * area_resource)))
632 v = min_slack_vertex;
638 if(total_muxes > 0 && mux_time_estimation > min_slack)
640 v = min_slack_vertex;
656 unsigned int total_muxes;
657 unsigned int n_shared;
658 double mux_area_estimation, mux_time_estimation;
659 estimate_muxes<false, true, C_vertex>(con_rel, mux_prec, mux_time_estimation, mux_area_estimation,
660 candidate_clique, total_muxes, n_shared, converter, HLSMgr, HLS,
662 return static_cast<size_t>(total_muxes);
705 c2s(cdfc_graph_info->c2s),
706 operation_writer(cdfc_graph_info->operation_graph.get(), 0)
717 operation_writer(out, c2s.find(v)->second);
740 const auto* edge_info = Cget_edge_info<CdfcEdgeInfo>(e, *printing_graph);
743 out <<
"[label=\"" << edge_info->edge_weight <<
"\"]";
747 out <<
"[color=red3]";
753 : c2s(_c2s), operation_graph(_operation_graph)
765 :
graph(cdfc_graphs_collection.get(), _selector)
771 :
graph(cdfc_graphs_collection.get(), _selector, vertices)
779 const auto* cdfc_graph_info = GetPointer<const CdfcGraphInfo>(
CGetGraphInfo());
781 const std::string output_directory =
collection->
parameters->getOption<std::string>(OPT_dot_directory) +
"/" +
782 behavioral_helper->get_function_name() +
"/";
783 if(!std::filesystem::exists(output_directory))
785 std::filesystem::create_directories(output_directory);
787 const std::string
full_name = output_directory + file_name;
788 const VertexWriterConstRef cdfc_writer(
new CdfcWriter(
this));
789 const EdgeWriterConstRef cdfc_edge_writer(
new CdfcEdgeWriter(
this));
790 InternalWriteDot<const CdfcWriter, const CdfcEdgeWriter>(
full_name, cdfc_writer, cdfc_edge_writer);
794 unsigned int _funId,
const DesignFlowManagerConstRef _design_flow_manager,
797 _hls_flow_step_specialization ?
798 _hls_flow_step_specialization :
801 small_normalized_resource_area(_parameters->IsParameter(
"small_normalized_resource_area") ?
802 _parameters->GetParameter<double>(
"small_normalized_resource_area") :
813 bool update_starting_time,
bool only_backward,
bool only_forward)
816 while(!sorted_vertices.empty())
818 vertex curr_vertex = *sorted_vertices.begin();
820 sorted_vertices.erase(curr_vertex);
821 double current_budget = slack_time[curr_vertex];
822 double new_current_budget = current_budget;
825 for(
const auto& ie : fdfg->
CGetInEdges(curr_vertex))
829 vertex src = boost::source(ie, *fdfg);
834 if(slack_time[src] > new_current_budget)
836 slack_time[src] = new_current_budget;
838 "---Reducing slack time of " +
GET_NAME(fdfg, src) +
" to " +
STR(slack_time[src]) +
839 " because of " +
GET_NAME(fdfg, curr_vertex));
840 sorted_vertices.insert(src);
842 else if(slack_time[src] < new_current_budget)
844 new_current_budget = slack_time[src];
862 if(slack_time[tgt] > new_current_budget)
864 if(update_starting_time)
866 starting_time[tgt] += slack_time[tgt] - new_current_budget;
868 "---Updating starting time of " +
GET_NAME(fdfg, tgt) +
" to " +
869 STR(starting_time[tgt]) +
" because of " +
GET_NAME(fdfg, curr_vertex));
871 slack_time[tgt] = new_current_budget;
873 "---Reducing slack time of " +
GET_NAME(fdfg, tgt) +
" to " +
874 STR(slack_time[tgt]) +
" because of " +
GET_NAME(fdfg, curr_vertex));
875 sorted_vertices.insert(tgt);
877 else if(slack_time[tgt] < new_current_budget)
879 new_current_budget = slack_time[tgt];
886 if(new_current_budget < current_budget)
888 sorted_vertices.insert(curr_vertex);
889 slack_time[curr_vertex] = new_current_budget;
901 for(boost::tie(ie, ie_end) = boost::in_edges(tgt, *fsdg); ie != ie_end; ++ie)
903 vertex src = boost::source(*ie, *fsdg);
904 unsigned int vw = HLSMgr->get_produced_value(functionId, src);
905 if(var_written == vw)
956 size_t total_modules_allocated = 0;
957 double total_resource_area = 0, total_DSPs = 0;
958 double total_area_muxes = 0;
960 unsigned int fu_unit;
972 if(n_shared_fu.find(fu_unit) == n_shared_fu.end())
974 n_shared_fu[fu_unit] = 1;
978 n_shared_fu[fu_unit] = 1 + n_shared_fu[fu_unit];
983 std::map<unsigned int, OpVertexSet, cdfc_resource_ordering_functor> candidate_vertices(r_functor);
991 ++total_modules_allocated;
992 total_resource_area += allocation_information->
get_area(fu_unit);
993 total_DSPs += allocation_information->
get_DSPs(fu_unit);
994 if(!allocation_information->
is_vertex_bounded(fu_unit) && n_shared_fu.find(fu_unit)->second != 1)
1000 easy_bound_vertices[fu_unit].insert(
operation);
1016 (!
parameters->isOption(OPT_rom_duplication) || !
parameters->getOption<
bool>(OPT_rom_duplication)))) &&
1018 n_shared_fu.find(fu_unit)->second == 1)
1020 ++total_modules_allocated;
1021 total_resource_area += allocation_information->
get_area(fu_unit);
1022 total_DSPs += allocation_information->
get_DSPs(fu_unit);
1030 easy_bound_vertices[fu_unit].insert(
operation);
1042 if(candidate_vertices.find(fu_unit) == candidate_vertices.end())
1044 candidate_vertices.insert(std::make_pair(fu_unit,
OpVertexSet(sdg)));
1046 candidate_vertices.find(fu_unit)->second.insert(
operation);
1047 all_candidate_vertices.insert(
operation);
1051 long clique_cputime = 0;
1052 long falseloop_cputime = 0;
1053 long weight_cputime = 0;
1054 long slack_cputime = 0;
1055 long clique_iteration_cputime = 0;
1056 unsigned int n_performance_conflicts = 0;
1059 if(!candidate_vertices.empty())
1061 std::vector<vertex> c2s;
1062 c2s.reserve(boost::num_vertices(*fdfg));
1074 std::list<vertex> sorted_vertices;
1079 double clock_period_resource_fraction =
HLS->
HLS_C->get_clock_period_resource_fraction();
1080 double actual_scheduling_clock_budget =
HLS->
HLS_C->get_clock_period() * clock_period_resource_fraction;
1081 const double clock_budget =
CLOCK_MARGIN * actual_scheduling_clock_budget;
1083 "---clock_budget=" +
STR(clock_budget) +
" setup_hold_time=" +
STR(setup_hold_time));
1085 for(
const auto operation : sorted_vertices)
1096 actual_scheduling_clock_budget);
1101 for(
const auto operation : boost::adaptors::reverse(sorted_vertices))
1105 double current_ending_time;
1108 current_ending_time = 0;
1114 const auto ii_time = allocation_information->
get_initiation_time(fu_type, statement_index);
1115 const auto n_cycles = allocation_information->
get_cycles(fu_type, statement_index);
1120 actual_scheduling_clock_budget) +
1123 else if(n_cycles > 1)
1125 current_ending_time = clock_budget - setup_hold_time;
1131 actual_scheduling_clock_budget);
1136 double current_budget = clock_budget - current_ending_time - setup_hold_time;
1138 "---Initial Current_budget/Slack for " +
GET_NAME(sdg,
operation) +
"=" +
STR(current_budget));
1139 if(current_budget < 0.0)
1141 current_budget = 0.0;
1144 for(boost::tie(oe, oe_end) = boost::out_edges(
operation, *fdfg); oe != oe_end; ++oe)
1154 current_ending_time =
std::max(ending_time[tgt], current_ending_time);
1155 current_budget =
std::min(current_budget, slack_time[tgt]);
1160 ending_time[
operation] = current_ending_time;
1172 " *** starting_time=" +
STR(starting_time.find(
operation)->second) +
1173 " *** latest_ending_time=" +
STR(ending_time.find(
operation)->second) +
1174 " *** slack_time=" +
STR(slack_time.find(
operation)->second));
1181 to_update.insert(sorted_vertices.begin(), sorted_vertices.end());
1186 "-->Updated Starting time *** Latest ending time *** Slacks");
1192 " *** starting_time=" +
STR(starting_time.find(
operation)->second) +
1193 " *** latest_ending_time=" +
STR(ending_time.find(
operation)->second) +
1194 " *** slack_time=" +
STR(slack_time.find(
operation)->second));
1203 "---Slack computed in " +
print_cpu_time(slack_cputime) +
" seconds");
1206 boost::graph_traits<graph>::vertices_size_type n_vert = boost::num_vertices(*fdfg);
1207 std::vector<boost::graph_traits<OpGraph>::vertices_size_type> rank_map(n_vert);
1208 std::vector<vertex> pred_map(n_vert);
1209 using const_vertex_index_pmap_t = boost::property_map<OpGraph, boost::vertex_index_t>::const_type;
1210 const_vertex_index_pmap_t cindex_pmap = boost::get(boost::vertex_index_t(), *fdfg);
1212 using op_rank_pmap_type =
1213 boost::iterator_property_map<std::vector<boost::graph_traits<OpGraph>::vertices_size_type>::iterator,
1214 const_vertex_index_pmap_t>;
1215 op_rank_pmap_type rank_pmap = boost::make_iterator_property_map(rank_map.begin(), cindex_pmap, rank_map[0]);
1217 using op_pred_pmap_type = boost::iterator_property_map<std::vector<vertex>::iterator, const_vertex_index_pmap_t>;
1218 op_pred_pmap_type pred_pmap = boost::make_iterator_property_map(pred_map.begin(), cindex_pmap, pred_map[0]);
1219 boost::disjoint_sets<op_rank_pmap_type, op_pred_pmap_type> ds(rank_pmap, pred_pmap);
1221 for(boost::tie(vi, vi_end) = boost::vertices(*fdfg); vi != vi_end; ++vi)
1229 for(
const auto& fu_eb : easy_bound_vertices)
1231 std::map<unsigned int, vertex> rep_vertex;
1232 for(
const auto& cur_v : fu_eb.second)
1234 auto vertex_index = fu->
get_index(cur_v);
1235 if(rep_vertex.find(vertex_index) == rep_vertex.end())
1237 rep_vertex[vertex_index] = cur_v;
1241 vertex rep = rep_vertex.find(vertex_index)->second;
1242 ds.union_set(cur_v, rep);
1243 starting_time[cur_v] = starting_time[rep] =
std::max(starting_time[rep], starting_time[cur_v]);
1244 ending_time[cur_v] = ending_time[rep] =
std::max(ending_time[rep], ending_time[cur_v]);
1251 for(boost::tie(vi, vi_end) = boost::vertices(*fdfg); vi != vi_end; ++vi)
1254 vertex rep = ds.find_set(s);
1256 if(rep == s && s2c.find(rep) == s2c.end())
1258 C = boost::add_vertex(*cdfc_bulk_graph);
1259 THROW_ASSERT(boost::get(boost::vertex_index, *cdfc_bulk_graph, C) == c2s.size(),
"unexpected case");
1262 else if(s2c.find(rep) == s2c.end())
1264 C = boost::add_vertex(*cdfc_bulk_graph);
1265 THROW_ASSERT(boost::get(boost::vertex_index, *cdfc_bulk_graph, C) == c2s.size(),
"unexpected case");
1278 "---add the control dependencies edges and the chained edges to the cdfc graph");
1281 for(boost::tie(ei, ei_end) =
boost::edges(*sdg); ei != ei_end; ++ei)
1283 vertex src = boost::source(*ei, *sdg);
1293 if(cdfc_src != cdfc_tgt)
1297 boost::tie(E, exists) = boost::edge(cdfc_src, cdfc_tgt, *cdfc_bulk_graph);
1302 boost::tie(E, exists) =
1315 double clock_cycle =
HLS->
HLS_C->get_clock_period() *
CLOCK_MARGIN * clock_period_resource_fraction;
1318 spec_hierarchical_clustering hc;
1321 for(
const auto& fu_cv : candidate_vertices)
1323 for(
const auto& cv : fu_cv.second)
1325 unsigned int fu_s1 = fu_cv.first;
1338 resource_area += allocation_information->
get_DSPs(fu_s1);
1342 hc.add_vertex(boost::get(boost::vertex_index, *fsdg, cv),
GET_NAME(fsdg, cv), fu->
get_assign(cv),
1347 for(
const auto& fu_cv : candidate_vertices)
1361 (setup_hold_time + starting_time[*cv1_it] + ending_time[*cv2_it] - starting_time[*cv2_it]))
1362 hc.add_tabu_pair(boost::get(boost::vertex_index, *fsdg, *cv1_it),
1363 boost::get(boost::vertex_index, *fsdg, *cv2_it));
1365 (setup_hold_time + starting_time[*cv2_it] + ending_time[*cv1_it] - starting_time[*cv1_it]))
1366 hc.add_tabu_pair(boost::get(boost::vertex_index, *fsdg, *cv1_it),
1367 boost::get(boost::vertex_index, *fsdg, *cv2_it));
1369 hc.add_tabu_pair(boost::get(boost::vertex_index, *fsdg, *cv1_it),
1370 boost::get(boost::vertex_index, *fsdg, *cv2_it));
1378 for(
const auto& fu_cv : candidate_vertices)
1380 for(
const auto& cv : fu_cv.second)
1382 unsigned int fu_s1 = fu_cv.first;
1386 std::vector<HLS_manager::io_binding_type> vars_read1 = HLSMgr->get_required_values(
HLS->
functionId, cv);
1387 unsigned int index = 0;
1388 for(
auto var_pair : vars_read1)
1390 unsigned int var_written = std::get<0>(var_pair);
1395 if(all_candidate_vertices.find(src) != all_candidate_vertices.end() &&
1398 hc.add_edge(boost::get(boost::vertex_index, *fsdg, src),
1399 boost::get(boost::vertex_index, *fsdg, tgt),
1407 for(tie(ei, ei_end) =
boost::edges(*fsdg); ei != ei_end; ++ei)
1409 vertex src = boost::source(*ei, *fsdg);
1411 if(all_candidate_vertices.find(src) == all_candidate_vertices.end())
continue;
1414 if(all_candidate_vertices.find(tgt) == all_candidate_vertices.end())
continue;
1416 hc.add_edge(boost::get(boost::vertex_index, *fsdg, src), boost::get(boost::vertex_index, *fsdg, tgt), 2*get_src_vertex(src, tgt, HLSMgr,
HLS->
functionId)+(
HLS->
chaining_information->
may_be_chained_ops(src, tgt)?1:0));
1432 "---Do a preliminary register binding to help the sharing of complex operations");
1433 if(
parameters->getOption<
bool>(OPT_shared_input_registers))
1441 ->CreateHLSFlowStep(
1456 for(
const auto& fu_cv : candidate_vertices)
1458 auto fu_s1 = fu_cv.first;
1460 "-->Considering fu " + allocation_information->
get_fu_name(fu_s1).first);
1462 std::string res_name = allocation_information->
get_fu_name(fu_s1).first;
1463 std::string lib_name =
HLS->
HLS_D->get_technology_manager()->get_library(res_name);
1467 bool disabling_slack_based_binding =
1470 (!
parameters->isOption(OPT_rom_duplication) || !
parameters->getOption<
bool>(OPT_rom_duplication)))) ||
1473 const auto local_mux_time =
1474 (disabling_slack_based_binding ? -std::numeric_limits<double>::infinity() : mux_time);
1475 const auto fu_prec = allocation_information->
get_prec(fu_s1);
1476 const auto cond1 =
compute_condition1(lib_name, allocation_information, local_mux_time, fu_s1);
1479 const auto cv_it_end = fu_cv.second.end();
1480 for(
auto cv_it = fu_cv.second.begin(); cv_it != cv_it_end;)
1482 auto cv1_it = cv_it;
1485 for(
auto cv2_it = cv_it; cv2_it != cv_it_end; ++cv2_it)
1490 "---Conflict between operations " +
GET_NAME(sdg, *cv1_it) +
"(" +
1496 if(!disabling_slack_based_binding && !allocation_information->
is_proxy_unit(fu_s1) &&
1498 allocation_information->
get_cycles(fu_s1, *cv1_it, sdg) <= 1 &&
1499 allocation_information->
get_cycles(fu_s1, *cv2_it, sdg) <= 1)
1503 (setup_hold_time + starting_time[*cv1_it] + ending_time[*cv2_it] - starting_time[*cv2_it]))
1506 "---Performance based problem in sharing " +
GET_NAME(sdg, *cv1_it) +
"(" +
1510 STR(setup_hold_time + starting_time[*cv1_it] + ending_time[*cv2_it] -
1511 starting_time[*cv2_it]));
1512 ++n_performance_conflicts;
1516 (setup_hold_time + starting_time[*cv2_it] + ending_time[*cv1_it] - starting_time[*cv1_it]))
1519 "---Performance based problem in sharing " +
GET_NAME(sdg, *cv1_it) +
"(" +
1523 STR(setup_hold_time + starting_time[*cv2_it] + ending_time[*cv1_it] -
1524 starting_time[*cv1_it]));
1525 ++n_performance_conflicts;
1540 _w =
weight_computation(cond1, cond2, *cv1_it, *cv2_it, local_mux_time, dfg, fu, slack_time,
1545 con_rel, controller_delay, fu_prec);
1555 boost::tie(E, exists) = boost::edge(s2c[*cv1_it], s2c[*cv2_it], *cdfc_bulk_graph);
1558 boost::tie(E, exists) = boost::add_edge(
1561 GET_NAME(sdg, *cv2_it) +
" -- " +
STR(s2c[*cv1_it]) +
"->" +
1567 " -- " +
STR(s2c[*cv1_it]) +
"->" +
STR(s2c[*cv2_it]));
1570 boost::tie(E, exists) = boost::edge(s2c[*cv2_it], s2c[*cv1_it], *cdfc_bulk_graph);
1573 boost::tie(E, exists) = boost::add_edge(
1576 GET_NAME(sdg, *cv1_it) +
" -- " +
STR(s2c[*cv2_it]) +
"->" +
1582 " -- " +
STR(s2c[*cv2_it]) +
"->" +
STR(s2c[*cv1_it]));
1588 "Null compatibility weight for " +
GET_NAME(sdg, *cv1_it) +
"(" +
1597 "<--Considered fu " + allocation_information->
get_fu_name(fu_s1).first);
1603 "---Weight computation completed in " +
print_cpu_time(weight_cputime) +
" seconds");
1613 if(
parameters->getOption<
bool>(OPT_print_dot))
1618 std::vector<int> cd_levels;
1619 cd_levels.resize(boost::num_vertices(*CD_chained_graph));
1621 std::deque<size_t> Csorted_vertices;
1623 auto sv_it_end = Csorted_vertices.end();
1624 for(
auto sv_it = Csorted_vertices.begin(); sv_it != sv_it_end; ++sv_it)
1626 cd_levels[*sv_it] = 0;
1628 for(boost::tie(ie, ie_end) = boost::in_edges(*sv_it, *CD_chained_graph); ie != ie_end; ++ie)
1630 if(boost::in_degree(boost::source(*ie, *CD_chained_graph), *CG) != 0)
1633 std::max(cd_levels[*sv_it], 1 + cd_levels[boost::get(boost::vertex_index, *CD_chained_graph,
1634 boost::source(*ie, *CD_chained_graph))]);
1639 std::max(cd_levels[*sv_it], cd_levels[boost::get(boost::vertex_index, *CD_chained_graph,
1640 boost::source(*ie, *CD_chained_graph))]);
1657 std::deque<cdfc_edge> candidate_edges;
1665 for(
const auto candidate : all_candidate_vertices)
1667 if(no_cycles.find(candidate) != no_cycles.end())
1673 if(cd_levels[boost::get(boost::vertex_index, *CG, start)] != 0 && boost::in_degree(start, *CG) != 0)
1677 "-->Search loops starting from -> " +
GET_NAME(sdg, candidate) +
" iteration " +
STR(k));
1681 no_cycles.insert(candidate);
1683 restart |= found_a_loop;
1684 THROW_ASSERT(!found_a_loop || candidate_edges.size() >= 1,
"something of unexpected happen");
1689 const auto ce_it_end = candidate_edges.end();
1690 auto ce_it = candidate_edges.begin();
1693 cdfc_vertex cand_src = boost::source(cand_e, *CG);
1695 int cand_level_difference =
std::abs(cd_levels[boost::get(boost::vertex_index, *CG, cand_src)] -
1696 cd_levels[boost::get(boost::vertex_index, *CG, cand_tgt)]);
1697 size_t cand_out_degree = boost::out_degree(cand_src, *CG) + boost::out_degree(cand_tgt, *CG);
1698 int cand_edge_weight = (*CG)[cand_e].weight;
1701 "-->Analyzing compatibility between operations " +
1702 GET_NAME(sdg, c2s[boost::get(boost::vertex_index, *CG, cand_src)]) +
"(" +
1703 sdg->
CGetOpNodeInfo(c2s[boost::get(boost::vertex_index, *CG, cand_src)])->GetOperation() +
1704 ")" +
" and " +
GET_NAME(sdg, c2s[boost::get(boost::vertex_index, *CG, cand_tgt)]) +
"(" +
1705 sdg->
CGetOpNodeInfo(c2s[boost::get(boost::vertex_index, *CG, cand_tgt)])->GetOperation() +
1706 ")" +
" - ld = " +
STR(cand_level_difference) +
" - d= " +
STR(cand_out_degree) +
1707 " - w = " +
STR(cand_edge_weight));
1709 for(; ce_it != ce_it_end; ++ce_it)
1714 int level_difference =
std::abs(cd_levels[boost::get(boost::vertex_index, *CG, src)] -
1715 cd_levels[boost::get(boost::vertex_index, *CG, tgt)]);
1716 size_t out_degree = boost::out_degree(src, *CG) + boost::out_degree(tgt, *CG);
1717 int edge_weight = (*CG)[e].weight;
1720 "---Analyzing compatibility between operations " +
1721 GET_NAME(sdg, c2s[boost::get(boost::vertex_index, *CG, src)]) +
"(" +
1722 sdg->
CGetOpNodeInfo(c2s[boost::get(boost::vertex_index, *CG, src)])->GetOperation() +
")" +
1723 " and " +
GET_NAME(sdg, c2s[boost::get(boost::vertex_index, *CG, tgt)]) +
"(" +
1724 sdg->
CGetOpNodeInfo(c2s[boost::get(boost::vertex_index, *CG, tgt)])->GetOperation() +
")" +
1725 " - ld = " +
STR(level_difference) +
" - d= " +
STR(out_degree) +
1726 " - w = " +
STR(edge_weight));
1727 if(level_difference > cand_level_difference ||
1728 (level_difference == cand_level_difference && out_degree > cand_out_degree) ||
1729 (level_difference == cand_level_difference && out_degree == cand_out_degree &&
1730 edge_weight < cand_edge_weight))
1735 cand_level_difference = level_difference;
1736 cand_out_degree = out_degree;
1737 cand_edge_weight = edge_weight;
1743 (*cdfc_bulk_graph)[cand_e].selector = 0;
1745 boost::tie(cand_e, exists) = boost::edge(cand_tgt, cand_src, *CG);
1747 (*cdfc_bulk_graph)[cand_e].selector = 0;
1750 "---Removed compatibility between operations " +
1751 GET_NAME(sdg, c2s[boost::get(boost::vertex_index, *CG, cand_src)]) +
"(" +
1752 sdg->
CGetOpNodeInfo(c2s[boost::get(boost::vertex_index, *CG, cand_src)])->GetOperation() +
1753 ")" +
" and " +
GET_NAME(sdg, c2s[boost::get(boost::vertex_index, *CG, cand_tgt)]) +
"(" +
1754 sdg->
CGetOpNodeInfo(c2s[boost::get(boost::vertex_index, *CG, cand_tgt)])->GetOperation() +
1756 candidate_edges.clear();
1765 "<--Searched loops starting from -> " +
GET_NAME(sdg, candidate) +
" iteration " +
1767 THROW_ASSERT(candidate_edges.empty(),
"candidate_cycle has to be empty");
1771 no_cycles.insert(candidate);
1782 "---False-loop computation completed in " +
print_cpu_time(falseloop_cputime) +
" seconds");
1785 if(
parameters->getOption<
bool>(OPT_print_dot))
1794 "---partition vertices for clique covering or bind the easy functional units");
1795 std::map<unsigned int, unsigned int> numModule;
1797 for(
const auto& fu_cv : candidate_vertices)
1799 fu_unit = fu_cv.first;
1800 for(
const auto cv : fu_cv.second)
1803 if(boost::out_degree(s2c[cv], *CG) == 0)
1805 unsigned int num = 0;
1806 if(numModule.find(fu_unit) == numModule.end())
1808 numModule[fu_unit] = 1;
1812 num = numModule[fu_unit]++;
1814 ++total_modules_allocated;
1815 total_resource_area += allocation_information->
get_area(fu_unit);
1816 total_DSPs += allocation_information->
get_DSPs(fu_unit);
1817 fu->
bind(cv, fu_unit, num);
1821 partitions[fu_unit].insert(s2c[cv]);
1822 identity_converter[cv] = cv;
1834 const unsigned int number_of_iterations = n_vert >
OP_THRESHOLD ? 2 : 10;
1835 const std::map<unsigned int, unsigned int> numModule_initial = numModule;
1836 const size_t total_modules_allocated_initial = total_modules_allocated;
1837 const double total_resource_area_initial = total_resource_area;
1838 double total_resource_area_prev = total_resource_area;
1839 const double total_DSPs_initial = total_DSPs;
1840 double total_DSPs_prev = total_DSPs;
1841 const double total_area_muxes_initial = total_area_muxes;
1842 double total_area_muxes_prev = total_area_muxes;
1847 if(
parameters->getOption<
int>(OPT_memory_banks_number) > 1 && !
parameters->isOption(OPT_context_switch))
1855 double total_area_best = 0;
1856 size_t total_modules_allocated_best = 0;
1857 double total_resource_area_best = 0;
1858 double total_area_muxes_best = 0;
1859 double total_DSPs_best = 0;
1861 for(
unsigned int iteration = 0; iteration < number_of_iterations; ++iteration)
1866 if(iteration > 1 && total_resource_area == total_resource_area_prev && total_DSPs == total_DSPs_prev &&
1867 total_area_muxes == total_area_muxes_prev)
1871 numModule = numModule_initial;
1872 total_modules_allocated = total_modules_allocated_initial;
1873 total_resource_area_prev = total_resource_area;
1874 total_resource_area = total_resource_area_initial;
1875 total_DSPs_prev = total_DSPs;
1876 total_DSPs = total_DSPs_initial;
1877 slack_time = slack_time_initial;
1878 starting_time = starting_time_initial;
1879 total_area_muxes_prev = total_area_muxes;
1880 total_area_muxes = total_area_muxes_initial;
1890 ->CreateHLSFlowStep(
1894 OPT_weighted_clique_register_algorithm))));
1900 ->CreateHLSFlowStep(
1912 for(
const auto& partition : partitions)
1914 THROW_ASSERT(partition.second.size() > 1,
"bad projection");
1915 auto vert_it_end = partition.second.end();
1916 const double mux_time =
1920 auto fu_prec = allocation_information->
get_prec(partition.first);
1923 "---controller_delay: " +
STR(controller_delay) +
1924 " resource normalized area=" +
STR(resource_area));
1926 "---mux_time: " +
STR(mux_time) +
1929 const auto disabling_slack_cond0 =
1932 (!
parameters->isOption(OPT_rom_duplication) || !
parameters->getOption<
bool>(OPT_rom_duplication))));
1933 const auto clique_covering_method = [&]() {
1934 if(disabling_slack_cond0)
1937 "DISABLING STD clique covering algorithm. Forced to BIPARTITE_MATCHING");
1941 ->clique_covering_algorithm;
1944 const auto res_name = allocation_information->
get_fu_name(partition.first).first;
1945 const auto lib_name =
HLS->
HLS_D->get_technology_manager()->get_library(res_name);
1946 const auto disabling_slack_based_binding =
1950 "unexpected condition");
1954 static_cast<unsigned>(partition.second.size()));
1956 for(
const auto v : partition.second)
1958 const auto el1_name =
GET_NAME(sdg, c2s[boost::get(boost::vertex_index, *CG, v)]) +
"(" +
1959 sdg->
CGetOpNodeInfo(c2s[boost::get(boost::vertex_index, *CG, v)])->GetOperation() +
1961 module_clique->add_vertex(c2s[boost::get(boost::vertex_index, *CG, v)], el1_name);
1967 size_t max_id = 0, curr_id;
1968 for(
const auto v : partition.second)
1970 const auto& running_states =
1972 for(
const auto state : running_states)
1974 const auto v2id_it = v2id.find(state);
1975 if(v2id_it == v2id.end())
1978 v2id[state] = max_id;
1983 curr_id = v2id_it->second;
1985 module_clique->add_subpartitions(curr_id, c2s[boost::get(boost::vertex_index, *CG, v)]);
1989 double local_mux_time =
1990 (disabling_slack_based_binding ? -std::numeric_limits<double>::infinity() : mux_time);
1991 const auto cond1 =
compute_condition1(lib_name, allocation_information, local_mux_time, partition.first);
1999 for(boost::tie(cg_ei, cg_ei_end) =
boost::edges(*CG_subgraph); cg_ei != cg_ei_end; ++cg_ei)
2001 vertex src = c2s[boost::get(boost::vertex_index, *CG_subgraph, boost::source(*cg_ei, *CG_subgraph))];
2002 vertex tgt = c2s[boost::get(boost::vertex_index, *CG_subgraph,
boost::target(*cg_ei, *CG_subgraph))];
2012 _w =
weight_computation(cond1, cond2, src, tgt, local_mux_time, dfg, fu, slack_time, starting_time,
2016 con_rel, controller_delay, fu_prec);
2019 module_clique->add_edge(src, tgt, _w);
2023 THROW_ASSERT(!disabling_slack_based_binding,
"unexpected condition");
2026 if(
parameters->getOption<
bool>(OPT_print_dot))
2028 const auto output_directory =
2029 parameters->getOption<std::string>(OPT_dot_directory) +
"/" + functionName +
"/";
2030 if(!std::filesystem::exists(output_directory))
2032 std::filesystem::create_directories(output_directory);
2034 const auto file_name =
2035 output_directory +
"MB_" + allocation_information->
get_string_name(partition.first) +
".dot";
2036 module_clique->writeDot(file_name);
2044 "unexpected condition");
2047 "Defining resource constraints for : " + allocation_information->
get_string_name(partition.first) +
2049 module_clique->suggest_min_resources(allocation_information->
get_number_channels(partition.first));
2052 module_clique->max_resources(allocation_information->
get_number_channels(partition.first));
2064 if(var && !HLSMgr->Rmem->is_private_memory(var))
2066 module_clique->min_resources(allocation_information->
get_number_channels(partition.first));
2070 "Starting clique covering on a graph with " +
STR(partition.second.size()) +
2071 " vertices for " + allocation_information->
get_string_name(partition.first));
2074 if(disabling_slack_based_binding)
2082 "Number of cliques covering the graph: " +
STR(module_clique->num_vertices()) +
" for " +
2084 if(module_clique->num_vertices() == 0 ||
2086 module_clique->num_vertices() > allocation_information->
get_number_channels(partition.first)))
2088 if(disabling_slack_cond0)
2099 static_cast<unsigned>(partition.second.size()));
2100 for(
auto vert_it = partition.second.begin(); vert_it != vert_it_end; ++vert_it)
2102 const auto el1_name =
2103 GET_NAME(sdg, c2s[boost::get(boost::vertex_index, *CG, *vert_it)]) +
"(" +
2104 sdg->
CGetOpNodeInfo(c2s[boost::get(boost::vertex_index, *CG, *vert_it)])->GetOperation() +
")";
2105 module_clique->add_vertex(c2s[boost::get(boost::vertex_index, *CG, *vert_it)], el1_name);
2109 size_t max_id = 0, curr_id;
2110 for(
const auto v : partition.second)
2114 for(
const auto state : running_states)
2116 const auto v2di_it = v2id.find(state);
2117 if(v2di_it == v2id.end())
2120 v2id[state] = max_id;
2125 curr_id = v2di_it->second;
2127 module_clique->add_subpartitions(curr_id, c2s[boost::get(boost::vertex_index, *CG, v)]);
2135 for(boost::tie(cg_ei, cg_ei_end) =
boost::edges(*CG_subgraph0); cg_ei != cg_ei_end; ++cg_ei)
2138 c2s[boost::get(boost::vertex_index, *CG_subgraph0, boost::source(*cg_ei, *CG_subgraph0))];
2140 c2s[boost::get(boost::vertex_index, *CG_subgraph0,
boost::target(*cg_ei, *CG_subgraph0))];
2149 _w =
weight_computation(cond1, cond2, src, tgt, local_mux_time, dfg, fu, slack_time, starting_time,
2153 con_rel, controller_delay, fu_prec);
2156 module_clique->add_edge(src, tgt, _w);
2168 "unexpected condition");
2170 module_clique->suggest_min_resources(allocation_information->
get_number_channels(partition.first));
2173 module_clique->max_resources(allocation_information->
get_number_channels(partition.first));
2180 if(var && !HLSMgr->Rmem->is_private_memory(var))
2182 module_clique->min_resources(allocation_information->
get_number_channels(partition.first));
2193 "unexpected condition");
2195 module_clique->num_vertices() > allocation_information->
get_number_channels(partition.first) &&
2198 THROW_ERROR(
"Something of wrong happen: no feasible solution exist for module binding: " +
2199 res_name +
"[" +
STR(module_clique->num_vertices()) +
"]");
2206 const auto area_resource = allocation_information->
get_area(partition.first) +
2207 100 * allocation_information->
get_DSPs(partition.first);
2210 controller_delay, mrbs);
2212 HLSMgr, area_resource, con_rel),
2216 "Number of cliques covering the graph: " +
STR(module_clique->num_vertices()) +
" for " +
2218 total_modules_allocated += module_clique->num_vertices();
2221 unsigned int Tot_mux = 0;
2224 unsigned int delta_nclique = 0;
2225 for(
unsigned int i = 0; i < module_clique->num_vertices(); ++i)
2227 const auto clique_temp = module_clique->get_clique(i);
2228 if(clique_temp.empty())
2234 const auto clique = clique_temp;
2237 clique.insert(clique_temp.begin(), clique_temp.end());
2242 THROW_ASSERT(fu_unit == partition.first,
"unexpected case");
2243 unsigned int num = 0;
2244 if(numModule.find(fu_unit) == numModule.end())
2246 numModule[fu_unit] = 1;
2250 num = numModule[fu_unit]++;
2252 total_resource_area += allocation_information->
get_area(fu_unit);
2253 total_DSPs += allocation_information->
get_DSPs(fu_unit);
2255 unsigned int total_muxes;
2256 unsigned int n_shared;
2258 double mux_area_estimation, mux_time_estimation;
2259 estimate_muxes<true, false>(con_rel, fu_prec, mux_time_estimation, mux_area_estimation, clique,
2261 Tot_mux += total_muxes;
2262 total_area_muxes += mux_area_estimation;
2264 "---estimate area muxes=" +
STR(mux_area_estimation));
2266 "---estimate delay muxes=" +
STR(mux_time_estimation));
2269 "---Sharing degree for " + allocation_information->
get_string_name(fu_unit) +
"_" +
2270 STR(num) +
" = " +
STR(clique.size()));
2272 double max_starting_time = 0.0;
2273 for(
const auto current_vert : clique)
2275 max_starting_time =
std::max(max_starting_time, starting_time[current_vert]);
2277 if(max_starting_time < controller_delay && total_muxes > 0)
2279 max_starting_time = controller_delay;
2282 bool first_vertex =
true;
2283 bool first_vertex_has_negative_slack =
false;
2285 for(
const auto current_vert : clique)
2287 const auto node_id = sdg->
CGetOpNodeInfo(current_vert)->GetNodeId();
2289 if(!first_vertex && (!disabling_slack_based_binding &&
2290 ((slack_time[current_vert] - (max_starting_time - starting_time[current_vert]) -
2291 mux_time_estimation) < 0 ||
2292 first_vertex_has_negative_slack) &&
2296 " negative slack: solution is not feasible");
2297 fu->
bind(current_vert, fu_unit, numModule[fu_unit]);
2301 "---" +
GET_NAME(sdg, current_vert) +
"(" +
2304 STR(numModule[fu_unit]) +
")");
2306 numModule[fu_unit]++;
2307 total_resource_area += allocation_information->
get_area(fu_unit);
2308 total_DSPs += allocation_information->
get_DSPs(fu_unit);
2309 total_modules_allocated++;
2315 first_vertex =
false;
2317 fu->
bind(current_vert, fu_unit, num);
2321 "---" +
GET_NAME(sdg, current_vert) +
"(" +
2326 slack_time[current_vert] = slack_time[current_vert] -
2327 (max_starting_time - starting_time[current_vert]) - mux_time_estimation;
2328 if(slack_time[current_vert] < 0)
2330 first_vertex_has_negative_slack =
true;
2332 starting_time[current_vert] = max_starting_time;
2333 to_update.insert(current_vert);
2347 to_update.insert(current_vert);
2365 "---cdfc mux estimation " +
STR(Tot_mux) +
" -- Number of cliques covering the graph: " +
2366 STR(module_clique->num_vertices() + delta_nclique) +
" " + functionName +
"_" +
2368 STR(partition.second.size()) +
" vertices");
2370 if(iteration == 0 || total_area_best > total_area_muxes + total_resource_area)
2373 total_area_best = total_area_muxes + total_resource_area;
2374 total_modules_allocated_best = total_modules_allocated;
2375 total_resource_area_best = total_resource_area;
2376 total_area_muxes_best = total_area_muxes;
2377 total_DSPs_best = total_DSPs;
2383 "---Iteration " +
STR(iteration) +
" completed in " +
2388 "---total_resource_area=" +
STR(total_resource_area) +
", total_DSPs=" +
STR(total_DSPs) +
2389 ", total_area_muxes=" +
STR(total_area_muxes));
2393 std::swap(fu_best, fu);
2394 std::swap(total_modules_allocated_best, total_modules_allocated);
2395 std::swap(total_resource_area_best, total_resource_area);
2396 std::swap(total_area_muxes_best, total_area_muxes);
2397 std::swap(total_DSPs_best, total_DSPs);
2402 "---Clique covering computation completed in " +
print_cpu_time(clique_cputime) +
" seconds");
2411 "-->Module binding information for function " +
2412 HLSMgr->CGetFunctionBehavior(
funId)->CGetBehavioralHelper()->get_function_name() +
":");
2414 "---Number of modules instantiated: " +
STR(total_modules_allocated));
2416 "---Number of performance conflicts: " +
STR(n_performance_conflicts));
2418 "---Estimated resources area (no Muxes and address logic): " +
STR(total_resource_area));
2421 "---Total estimated area: " +
STR(total_area_muxes + total_resource_area));
2427 "Time to perform module binding: " +
print_cpu_time(step_time) +
" seconds");
2440 std::vector<bool> visited(boost::num_vertices(*cdfc),
false);
2441 std::vector<bool> cg_visited(boost::num_vertices(*cg),
false);
2442 std::vector<bool> cdfc_visited(boost::num_vertices(*cg),
false);
2443 cg_visited[boost::get(boost::vertex_index, *cg, start)] =
true;
2445 for(boost::tie(oe_cg, oe_end_cg) = boost::out_edges(start, *cg); oe_cg != oe_end_cg; ++oe_cg)
2448 visited[boost::get(boost::vertex_index, *cdfc, tgt)] =
true;
2451 candidate_edges.push_front(*oe_cg);
2454 visited[boost::get(boost::vertex_index, *cdfc, tgt)] =
false;
2461 std::deque<cdfc_edge>& candidate_edges, std::vector<bool>& visited,
2462 std::vector<bool>& cg_visited, std::vector<bool>& cdfc_visited)
2469 if(cdfc_visited[boost::get(boost::vertex_index, *cdfc, src)])
2473 cdfc_visited[boost::get(boost::vertex_index, *cdfc, src)] =
true;
2474 for(boost::tie(oe_cdfc, oe_end_cdfc) = boost::out_edges(src, *cdfc); oe_cdfc != oe_end_cdfc; ++oe_cdfc)
2477 if(!visited[boost::get(boost::vertex_index, *cdfc, tgt)])
2479 visited[boost::get(boost::vertex_index, *cdfc, tgt)] =
true;
2482 boost::tie(cg_e, is_cg_edge) = boost::edge(src, tgt, *cg);
2484 cg_visited, cdfc_visited))
2488 visited[boost::get(boost::vertex_index, *cdfc, tgt)] =
false;
2497 std::deque<cdfc_edge>& candidate_edges,
2498 std::vector<bool>& visited, std::vector<bool>& cg_visited,
2499 std::vector<bool>& cdfc_visited)
2506 if(cg_visited[boost::get(boost::vertex_index, *cg, src)])
2510 cg_visited[boost::get(boost::vertex_index, *cg, src)] =
true;
2512 for(boost::tie(oe_cdfc, oe_end_cdfc) = boost::out_edges(src, *cdfc); oe_cdfc != oe_end_cdfc; ++oe_cdfc)
2515 if(!visited[boost::get(boost::vertex_index, *cdfc, tgt)])
2517 visited[boost::get(boost::vertex_index, *cdfc, tgt)] =
true;
2524 candidate_edges.push_front(cg_e);
2536 visited[boost::get(boost::vertex_index, *cdfc, tgt)] =
false;
2556 if(slack_time.find(v)->second < 2 * mux_time)
2561 auto fu_s1 = fu->get_assign(v);
2609 std::vector<HLS_manager::io_binding_type> vars_read1 = HLSMgr->get_required_values(
HLS->
functionId, v);
2610 if(vars_read1.size() > 1)
2622 if(exec_time < 1.0 || resource_area < 0.5)
2646 spec_hierarchical_clustering& hc,
2649 unsigned long long prec)
2652 "-->Weight computation of " +
GET_NAME(fsdg, v1) +
"-->" +
GET_NAME(fsdg, v2));
2654 size_t threshold1, threshold2;
2655 size_t in1 = con_rel.find(v1)->second.size();
2656 size_t in2 = con_rel.find(v2)->second.size();
2657 unsigned int total_muxes = 0;
2661 size_t n_inputs = in1;
2662 threshold1 = 2 * n_inputs;
2664 std::vector<vertex> cluster(2);
2669 unsigned int n_shared;
2670 double mux_area_estimation, mux_time_estimation;
2671 estimate_muxes<false, false>(con_rel, prec, mux_time_estimation, mux_area_estimation, cluster, total_muxes,
2674 "---total_muxes=" +
STR(total_muxes) +
" n_shared=" +
STR(n_shared) +
2675 " n_inputs=" +
STR(n_inputs));
2679 if(total_muxes > n_inputs)
2685 _w = 1 + n_inputs + n_inputs - total_muxes;
2688 threshold2 = threshold1 + n_shared;
2692 threshold1 = 2 *
std::max(in1, in2);
2693 threshold2 = threshold1;
2697 double max_starting_time =
std::max(starting_time.find(v1)->second, starting_time.find(v2)->second);
2698 if(max_starting_time < controller_delay && total_muxes > 0)
2700 max_starting_time = controller_delay;
2702 double v1_slack, v2_slack;
2703 v1_slack = slack_time.find(v1)->second - (max_starting_time - starting_time.find(v1)->second);
2704 v2_slack = slack_time.find(v2)->second - (max_starting_time - starting_time.find(v2)->second);
2707 "---cond1=" + (cond1 ? std::string(
"T") : std::string(
"F")) +
2708 " cond2=" + (cond2 ? std::string(
"T") : std::string(
"F")));
2710 "---Weight before=" +
STR(_w) +
" v1_slack=" +
STR(v1_slack) +
" v2_slack=" +
STR(v2_slack) +
2711 " threshold=" +
STR(threshold1) +
" resource_type=" +
" mux_time=" +
STR(mux_time) +
2712 " prec=" +
STR(prec));
2714 if(cond1 && _w <= threshold1 && ((v1_slack < mux_time) || (v2_slack < mux_time)))
2722 hc.pair_weight(boost::get(boost::vertex_index, *fsdg, v1), boost::get(boost::vertex_index, *fsdg, v2));
2723 int delta =
static_cast<int>(
static_cast<double>(threshold1) * p_weight);
2729 std::cerr <<
"Before " << _w_saved <<
" " <<
GET_NAME(fsdg, v1) <<
"(" 2731 <<
"-" <<
GET_NAME(fsdg, v2) << std::endl;
2732 std::cerr <<
"After " << _w << std::endl;
2736 else if((cond2 && _w <= threshold2))
2747 return static_cast<int>(_w);
#define TYPE_SWITCH
constant identifying the node type of a SWITCH operation.
OpEdgeSet CGetInEdges(const vertex v) const
Return the edge ingoing in a vertex.
void operator()(std::ostream &out, const EdgeDescriptor &e) const override
Operator which print label of an EdgeDescriptor.
Class specification to contain liveness information.
unsigned int get_register(unsigned int sv) const
return the register index where the storage value is stored
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
const HLS_managerRef HLSMgr
information about all the HLS synthesis
int GetSelector() const
Return the selector of this graph.
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;.
Module binding based on the analysis of the control data flow chained graph.
boost::graph_traits< graph >::out_edge_iterator OutEdgeIterator
out_edge_iterator definition.
const OpWriter operation_writer
The functor used to print labels which correspond to vertices of the graph to be printed.
#define GET_TYPE(data, vertex_index)
Helper macro returning the type associated with a node.
CdfcEdgeWriter(const CdfcGraph *_printing_graph)
Constructor.
void back_edge(const Edge &e, Graph &g)
std::vector< vertex > & c2s
const OpGraphConstRef data
File containing functions and utilities to support the printing of debug messagges.
The info associated with a cdfc graph.
#define PRINT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
const ParameterConstRef parameters
Set of input parameters.
std::string ToString() const
Print this node as string in gimple format.
This file contains the structures needed to manage a graph that will represent the state transition g...
const CustomOrderedSet< vertex > & get_state_where_end(vertex op) const
return in which support vertex the operation is ending
Base class storing user data information to the whole graph.
This header file includes four different algorithms heuristically solving the clique covering problem...
#define FB_DFG_SCA_SELECTOR
Data flow graph edge selector between computed on scalars.
#define TYPE_MULTIIF
constant identifying the a multi-way if
#define TYPE_VPHI
constant string identifying an operation node of type virtual phi-nodes
refcount< fu_binding > fu_bindingRef
RefCount type definition of the fu_binding class structure.
#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.
Weighted clique covering register allocation procedure.
#define TYPE_IF
constant identifying the node type of an IF operation.
const CustomUnorderedMap< vertex, vertex > & c2s
const int output_level
The output level.
boost::graph_traits< cdfc_graph >::in_edge_iterator cdfc_in_edge_iterator
in_edge_iterator definition.
bool get_ports_are_swapped(vertex v) const
Check if vertex v has its ports swapped or not.
static fu_bindingRef create_fu_binding(const HLS_managerConstRef _HLSMgr, const unsigned int _function_id, const ParameterConstRef _parameters)
create_fu_binding: factory method for fu_binding
Predicate functor object used to select the proper set of edges.
AbsControlStep get_cstep(const vertex &op) const
Returns the clock cycle where the given operation has been scheduled.
#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
absl::btree_map< T, U, Compare, Alloc > CustomOrderedMap
CdfcEdgeInfo(const int edge_weight)
Constructor.
unsigned int get_assign(const vertex &v) const
Returns the functional unit assigned to the vertex.
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.
Class specification of the graph structures.
const HLS_deviceRef HLS_D
reference to the information representing the target for the synthesis
boost::graph_traits< graph >::in_edge_iterator InEdgeIterator
in_edge_iterator definition.
static bool is_parameter(const tree_managerConstRef &TM, const unsigned int index)
return true in case the index corresponds to a parameter in ssa form or not
AbsControlStep get_cstep_end(const vertex &op) const
Return the last clock cycle in which the operation execute.
AllocationInformationRef allocation_information
Store the technology information.
const OpVertexSet CGetOperations() const
Return the vertices belonging to the graph.
bool false_loop_search_cdfc_more(cdfc_vertex src, unsigned int level, unsigned k, cdfc_vertex start, const cdfc_graphConstRef &cdfc, const cdfc_graphConstRef &cg, std::deque< cdfc_edge > &candidate_edges, std::vector< bool > &visited, std::vector< bool > &cg_visited, std::vector< bool > &cdfc_visited)
void initialize_connection_relation(connection_relation &con_rel, const OpVertexSet &all_candidate_vertices)
refcount< boost_cdfc_graph > boost_cdfc_graphRef
DesignFlowStep_Status InternalExec() override
Execute the step.
const CustomUnorderedMap< vertex, double > & starting_time
CliqueCovering_Algorithm
Defines all clique covering algorithm.
Class specification of the manager of the technology library data structures.
void operator()(std::ostream &out, const vertex &v) const override
Operator used to print the label of a vertex.
CustomUnorderedMap< vertex, std::vector< CustomOrderedSet< std::pair< conn_code, std::pair< unsigned int, vertex > >> >> connection_relation
put into relation an operation vertex with its sources op vertex -> vector of port index -> set of pa...
#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.
topological_based_sorting_visitor(std::vector< vertex > &_c2s, const OpGraphConstRef _sdg, OutputIterator _iter)
const tree_nodeConstRef CGetTreeNode(const unsigned int i) const
A set of operation vertices.
boost::filtered_graph< boost_cdfc_graph, cdfc_graph_edge_selector< boost_cdfc_graph >, cdfc_graph_vertex_selector< boost_cdfc_graph > > cdfc_graph
compatibility graph
#define TYPE_PHI
constant string identifying an operation node of type PHI
void WriteDot(const std::string &file_name, const int detail_level=0) const
Writes this graph in dot format.
bool are_in_conflict(vertex op1, vertex op2) const
states if two operations are in conflict (i.e.
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
const AllocationInformationConstRef allocation_information
copy of the order: control step associated with the vertices.
cdfc_module_binding(const ParameterConstRef _parameters, const HLS_managerRef HLSMgr, unsigned int funId, const DesignFlowManagerConstRef design_flow_manager, const HLSFlowStepSpecializationConstRef hls_flow_step_specialization)
This is the constructor of the class.
bool can_be_clustered(vertex v, OpGraphConstRef fsdg, const fu_bindingConstRef fu, const CustomUnorderedMap< vertex, double > &slack_time, const double mux_time)
std::string GetSignature() const override
Return the contribution to the signature of a step given by the specialization.
boost::graph_traits< graph >::edge_iterator EdgeIterator
edge_iterator definition.
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.
#define TYPE_LABEL
A vertex is of type TYPE_LABEL when it is a target of a goto expression.
OpEdgeSet CGetOutEdges(const vertex v) const
Return the edge outgoing from a vertex.
CustomUnorderedMap< vertex, bool > can_be_clustered_table
record if a vertex has to be clustered or not
const OpNodeInfoConstRef CGetOpNodeInfo(const vertex node) const
Returns the info associated with a node.
~CdfcGraphsCollection() override
Destructor.
#define TYPE_EXIT
constant identifying the node type of an exit node.
#define START_TIME(time_var)
Macro used to store the start time into time_var.
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
System dependence graph with feedback.
fu_bindingRef Rfu
Store the refcounted functional unit binding of the operations.
Functor used to reduce the size of clique: the rationale of filtering is that too many sharing may cr...
#define MODULE_BINDING_MUX_MARGIN
Factory for hls flow step.
ScheduleRef Rsch
Store the refcounted scheduling of the operations.
CdfcGraph(const CdfcGraphsCollectionRef cdfc_graphs_collection, const int selector)
Constructor.
Data structure used to store the register binding of variables.
Base class for step of design flow.
StorageValueInformationRef storage_value_information
data-structure for storage values
void set_HLS(hlsRef _HLS)
#define TYPE_GOTO
A vertex is of type TYPE_GOTO when it is associated with a goto expression.
This class specifies the characteristic of a particular operation working on a given functional unit...
absl::flat_hash_map< T, U, Hash, Eq, Alloc > CustomUnorderedMap
void finish_vertex(const Vertex &u, Graph &g)
Data structure used to store the schedule of the operations.
const unsigned long long mux_prec
Functor used to write the content of a vertex to dotty file.
static const uint32_t k[]
static refcount< clique_covering< VertexType > > create_solver(CliqueCovering_Algorithm solver, unsigned int nvert)
Creates a reference to desired solver.
Class specification of the data structures used to manage technology information. ...
std::string GetKindText() const override
Return the string representation of this.
#define TYPE_EXTERNAL
constant identifying the node type of a EXTERNAL operation (a function call)
bool operator()(const unsigned int &a, const unsigned int &b) const
functor function used to compare two resources with respect to their area
static bool compute_condition1(const std::string &lib_name, const AllocationInformationConstRef allocation_information, double local_mux_time, unsigned int fu_s1)
cdfc_resource_ordering_functor(const AllocationInformationConstRef _allocation_soluton)
Constructor.
const double area_resource
void bind(const vertex &v, unsigned int unit, unsigned int index=std::numeric_limits< unsigned int >::max())
Binds an operation vertex to a functional unit.
const CliqueCovering_Algorithm clique_covering_algorithm
The cdfc module binding algorithm.
redefinition of set to manage ordered/unordered structures
#define STOP_TIME(time_var)
Macro used to store the elapsed time into time_var.
slack_based_filtering(const CustomUnorderedMap< vertex, double > &_slack_time, const CustomUnorderedMap< vertex, double > &_starting_time, double _controller_delay, unsigned long long _mux_prec, const hlsRef _HLS, const HLS_managerRef _HLSMgr, const double _area_resource, const connection_relation &_con_rel)
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
~cdfc_module_binding() override
Destructor.
const Wrefcount< const DesignFlowManager > design_flow_manager
The design flow manager.
Data structure used to store the functional-unit binding of the vertices.
#define DEFAULT_SMALL_NORMALIZED_RESOURCE_AREA
General class used to describe a graph in PandA.
const BehavioralHelperConstRef CGetBehavioralHelper() const
Returns the helper associated with the function.
boost::graph_traits< graph >::vertex_iterator VertexIterator
vertex_iterator definition.
Classes specification of the tree_node data structures.
CdfcGraphsCollection(const CdfcGraphInfoRef cdfc_graph_info, const ParameterConstRef parameters)
Constructor.
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
This file collects some utility functions and macros.
reg_bindingRef Rreg
Store the refcounted register binding of the variables.
~CdfcGraph() override
Destructor.
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
void update_slack_starting_time(const OpGraphConstRef fdfg, OpVertexSet &sorted_vertices, CustomUnorderedMap< vertex, double > &slack_time, CustomUnorderedMap< vertex, double > &starting_time, bool update_starting_time, bool only_backward, bool only_forward)
Data structure definition for HLS constraints.
const double small_normalized_resource_area
Threshold used in sharing of functional units.
livenessRef Rliv
data-structure containing the variable liveness
This file collects some utility functions.
void TopologicalSort(std::list< boost::graph_traits< graphs_collection >::vertex_descriptor > &sorted_vertices) const
Compute the topological order of the graph.
double GetStartingTime(const unsigned int operation) const
Return the starting time of the operation.
std::string print_cpu_time(long int t)
massage a long which represents a time interval in milliseconds, into a string suitable for output ...
const OpGraphConstRef sdg
boost::graph_traits< cdfc_graph >::edge_descriptor cdfc_edge
edge definition.
int weight_computation(bool cond1, bool cond2, vertex v1, vertex v2, const double mux_time, const OpGraphConstRef fdfg, const fu_bindingConstRef fu, const CustomUnorderedMap< vertex, double > &slack_time, CustomUnorderedMap< vertex, double > &starting_time, connection_relation &con_rel, double controller_delay, unsigned long long prec)
const std::string CliqueCovering_AlgorithmToString(const CliqueCovering_Algorithm clique_covering_algorithm)
Header include.
#define DFG_SCA_SELECTOR
Selectors used only in operation graphs; numbers continue from cdfg_edge_info.hpp.
refcount< T > lock() const
boost::adjacency_list< boost::vecS, boost::vecS, boost::bidirectionalS, boost::property< boost::vertex_index_t, std::size_t >, edge_cdfc_selector > boost_cdfc_graph
bulk compatibility graph
bool false_loop_search_cdfc_1(cdfc_vertex src, unsigned int level, unsigned k, cdfc_vertex start, const cdfc_graphConstRef &cdfc, const cdfc_graphConstRef &cg, std::deque< cdfc_edge > &candidate_edges, std::vector< bool > &visited, std::vector< bool > &cg_visited, std::vector< bool > &cdfc_visited)
bool false_loop_search(cdfc_vertex start, unsigned k, const cdfc_graphConstRef &cdfc, const cdfc_graphConstRef &cg, std::deque< cdfc_edge > &candidate_edges)
boost::graph_traits< cdfc_graph >::edge_iterator cdfc_edge_iterator
edge_iterator definition.
#define OUTPUT_LEVEL_PEDANTIC
verbose debugging print is performed.
CDFCModuleBindingSpecialization(const CliqueCovering_Algorithm clique_covering_algorithm)
Constructor.
const HLS_managerRef HLSMgr
Functor used to write the content of the edges to a dotty file.
const GraphInfoConstRef CGetGraphInfo() const
FIXME: this method should become protected and called by equivalent method in subclasses Get the grap...
CdfcWriter(const CdfcGraph *_printing_graph)
Constructor.
Data flow graph with feedback.
This package is used to define the storage value scheme adopted by the register allocation algorithms...
Predicate functor object used to select the proper set of vertices.
#define OUTPUT_LEVEL_VERY_PEDANTIC
verbose debugging print is performed.
const CustomUnorderedMap< vertex, double > & slack_time
Collect all structs used to write a graph in the dot format.
T * GetPointer(const refcount< U > &t)
Template function used to hide dynamic_cast The template parameter T represents a type of an object h...
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.
#define WORK_LIBRARY
working library.
#define INFINITE_UINT
UNSIGNED INT representing infinite.
const CustomOrderedSet< vertex > & get_state_where_run(vertex op) const
return in which support vertex the operation is running
hlsRef HLS
HLS data structure of the function to be analyzed.
This file collects some hash functors.
CdfcGraphInfo(const CustomUnorderedMap< vertex, vertex > &c2s, const OpGraphConstRef operation_graph)
Constructor.
Functor used to compare which of two resources has to be considered first during the binding...
Data structures used in operations graph.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
this class is used to manage the command-line or XML options.
const CdfcGraphInfo * cdfc_graph_info
The info associated with the graph to be printed.
static const int COMPATIBILITY_EDGE
void estimate_muxes(const connection_relation &con_rel, unsigned long long mux_prec, double &tot_mux_delay, double &tot_mux_area, const cluster_type &cluster, unsigned int &total_muxes, unsigned int &n_shared, const CustomUnorderedMap< vertex_type, vertex > &converter, const HLS_managerRef HLSMgr, const hlsRef HLS, int debug_level)
bool is_filtering() const override
unsigned int functionId
this is the identifier of the function to be implemented
#define TYPE_ENTRY
constant identifying the node type of an entry node.
boost::filtered_graph< boost_cc_compatibility_graph, cc_compatibility_graph_edge_selector< boost_cc_compatibility_graph >, cc_compatibility_graph_vertex_selector< boost_cc_compatibility_graph > > cc_compatibility_graph
compatibility graph
static bool compute_condition2(bool cond1, unsigned long long fu_prec, double resource_area, const double small_normalized_resource_area)
refcount< const cdfc_graph > cdfc_graphConstRef
refcount< cdfc_graph > cdfc_graphRef
refcount version of cdfc_graph
const HLS_constraintsRef HLS_C
store the HLS constraints
Class to manage mux-based interconnections based on the FSM controller.
int debug_level
The debug level.
double GetEndingTime(const unsigned int operation) const
Return the starting time of the operation.
boost::graph_traits< cdfc_graph >::vertex_descriptor cdfc_vertex
vertex definition
#define OUTPUT_LEVEL_VERBOSE
verbose debugging print is performed.
refcount< const HLSFlowStepSpecialization > HLSFlowStepSpecializationConstRef
const refcount definition of the class
#define TYPE_RET
constant string identifying an operation node of type return expr
graphs_collection * collection
The graph collection.
void topological_based_sorting(const VertexListGraph &g, std::vector< vertex > &c2s, const OpGraphConstRef sdg, OutputIterator result, const boost::bgl_named_params< P, T, R > ¶ms)
bool select_candidate_to_remove(const CustomOrderedSet< C_vertex > &candidate_clique, C_vertex &v, const CustomUnorderedMap< C_vertex, vertex > &converter, const cc_compatibility_graph &cg) const override
#define DEBUG_LEVEL_VERBOSE
verbose debugging print is performed.
boost::graph_traits< cc_compatibility_graph >::vertex_descriptor C_vertex
cc_compatibility_graph vertex
const connection_relation & con_rel
Data structure definition for high-level synthesis flow.
boost::graph_traits< cdfc_graph >::out_edge_iterator cdfc_out_edge_iterator
out_edge_iterator definition.
#define NULL_VERTEX
null vertex definition
Datastructure to represent memory information in high-level synthesis.
#define PROXY_LIBRARY
proxy library
unsigned int get_index(const vertex &v) const
Returns the index of functional unit assigned to the vertex.
Generic class managing module binding algorithms.
Class specification of the manager of the tree structures extracted from the raw file.
const HLSFlowStepSpecializationConstRef hls_flow_step_specialization
The information about specialization.
HLS specialization of generic_device.
A brief description of the C++ Header File.
ChainingInformationRef chaining_information
Store the refcounted chaining info.
size_t clique_cost(const CustomOrderedSet< C_vertex > &candidate_clique, const CustomUnorderedMap< C_vertex, vertex > &converter) const override
boost::graph_traits< graph >::edge_descriptor EdgeDescriptor
edge definition.
#define THROW_ASSERT(cond, str_expr)
helper function used to check an assert and if needed to throw an error in a standard way ...