86 const DesignFlowManagerConstRef _design_flow_manager,
88 :
memory_allocation(_parameters, _HLSMgr, _design_flow_manager, _hls_flow_step_type, _hls_flow_step_specialization),
89 user_defined_base_address(UINT64_MAX)
98 const auto TM =
HLSMgr->get_tree_manager();
99 const auto FB =
HLSMgr->CGetFunctionBehavior(fun_id);
100 const auto BH = FB->CGetBehavioralHelper();
101 const auto var_name = BH->PrintVariable(var_id);
102 const auto fun_name = BH->get_function_name();
103 const auto memory_allocation_policy = FB->GetMemoryAllocationPolicy();
105 bool is_internal =
false;
118 if(!multiple_top_call_graph)
120 const auto tn = TM->CGetTreeNode(var_id);
121 switch(memory_allocation_policy)
125 const auto vd = GetPointer<const var_decl>(tn);
126 if(vd && (vd->static_flag || (vd->scpe &&
GET_CONST_NODE(vd->scpe)->get_kind() != translation_unit_decl_K)))
130 if(GetPointer<const string_cst>(tn))
134 if(
HLSMgr->Rmem->is_parm_decl_copied(var_id) ||
HLSMgr->Rmem->is_parm_decl_stored(var_id))
142 const auto vd = GetPointer<const var_decl>(tn);
143 if(vd && (vd->static_flag || !vd->scpe ||
GET_CONST_NODE(vd->scpe)->get_kind() == translation_unit_decl_K))
147 if(GetPointer<const string_cst>(tn))
151 if(
HLSMgr->Rmem->is_parm_decl_copied(var_id) ||
HLSMgr->Rmem->is_parm_decl_stored(var_id))
175 if(GetPointer<const gimple_call>(tn))
186 const auto current_function_ID = CG->get_function(current_vertex);
188 if(HLSMgr->Rfuns->is_a_proxied_function(current_function_name))
190 return CG->GetVertex(HLSMgr->Rfuns->get_proxy_mapping(current_function_name));
192 return current_vertex;
197 if(
parameters->isOption(OPT_xml_memory_allocation))
199 const auto XMLfilename =
parameters->getOption<std::string>(OPT_xml_memory_allocation);
205 const auto node = parser.
get_document()->get_root_node();
206 const auto& list = node->get_children();
207 for(
const auto& l : list)
209 const auto child = GetPointer<xml_element>(l);
214 if(child->get_name() ==
"memory_allocation")
216 auto base_address = UINT64_MAX;
217 if(
CE_XVM(base_address, child))
222 for(
const auto& it : child->get_children())
224 const auto mem_node = GetPointer<xml_element>(it);
229 if(mem_node->get_name() ==
"object")
231 std::string is_internal;
232 if(!
CE_XVM(is_internal, mem_node))
237 if(is_internal ==
"T")
239 if(!
CE_XVM(scope, mem_node))
241 THROW_ERROR(
"expected the scope attribute when the object is internal");
245 if(!
CE_XVM(name, mem_node))
253 else if(is_internal ==
"F")
256 if(
CE_XVM(scope, mem_node))
264 if(!
CE_XVM(name, mem_node))
274 THROW_ERROR(
"unexpected value for is_internal attribute");
283 for(
const auto& var_obj : user_obj.second)
289 THROW_ERROR(
"An allocated object cannot be both internal and external: " + var_obj +
" in function " +
296 THROW_ERROR(
"An allocated object cannot be both internal and external: " + var_obj +
" in function " +
309 using func_id_t =
unsigned int;
310 using top_id_t = func_id_t;
311 using var_id_t =
unsigned int;
313 long int step_time = 0;
320 const auto TM =
HLSMgr->get_tree_manager();
321 const auto HLS_D =
HLSMgr->get_HLS_device();
323 const auto initial_internal_address_p =
parameters->isOption(OPT_initial_internal_address);
324 const auto initial_internal_address = initial_internal_address_p ?
325 parameters->getOption<
unsigned int>(OPT_initial_internal_address) :
327 const auto unaligned_access_p =
328 parameters->isOption(OPT_unaligned_access) &&
parameters->getOption<
bool>(OPT_unaligned_access);
329 const auto assume_aligned_access_p =
331 const auto max_bram = HLS_D->get_parameter<
unsigned int>(
"BRAM_bitsize_max");
335 parameters->getOption<
unsigned long long int>(OPT_base_address);
336 const auto null_pointer_check = [&]() {
337 if(
parameters->isOption(OPT_gcc_optimizations))
340 if(gcc_parameters.find(
"no-delete-null-pointer-checks") != gcc_parameters.end())
351 initial_internal_address_p, initial_internal_address,
HLSMgr->Rget_address_bitsize());
354 const auto CGM =
HLSMgr->CGetCallGraphManager();
361 std::set<func_id_t> top_functions;
364 const auto root_functions = CGM->GetRootFunctions();
365 top_functions.insert(root_functions.begin(), root_functions.end());
366 const auto subgraph_from = [&](
const vertex& top_vertex,
bool is_addr =
false,
bool include_shared =
true) {
367 const auto top_function = CGM->get_function(top_vertex);
369 preset.insert(top_vertex);
370 const auto reached_from_top = CGM->GetReachedFunctionsFrom(top_function);
371 const auto is_dominated = [&](
const vertex& v) {
372 BOOST_FOREACH(
EdgeDescriptor e, boost::in_edges(v, *CGM->CGetCallGraph()))
374 if(!reached_from_top.count(CGM->get_function(boost::source(e, *CGM->CGetCallGraph()))))
381 for(
const auto& funID : reached_from_top)
383 if(!top_functions.count(funID))
385 const auto funV = CGM->GetVertex(funID);
386 if(include_shared || is_dominated(funV))
392 const auto presub = CGM->CGetCallSubGraph(preset);
394 subset.insert(top_vertex);
395 const auto update_vertices = !is_addr;
398 reachable_vertices[top_function].insert(top_vertex);
399 all_reachable_vertices.insert(top_vertex);
401 for(
const auto& v : preset)
403 if(presub->IsReachable(top_vertex, v))
408 reachable_vertices[top_function].insert(v);
409 all_reachable_vertices.insert(v);
413 return CGM->CGetCallSubGraph(subset);
415 const auto push_allocation_order = [&](std::vector<func_id_t>& allocation_order, top_id_t top_function,
416 bool include_shared =
true) {
417 const auto top_vertex = CGM->GetVertex(top_function);
418 const auto subgraph = subgraph_from(top_vertex,
false, include_shared);
419 cg[top_function] = subgraph;
421 cg_dominators[top_function] =
424 cg_dominator_map[top_function] = cg_dominators.at(top_function)->get_dominator_map();
425 std::list<vertex> sorted;
426 subgraph->TopologicalSort(sorted);
427 for(
const auto& v : sorted)
429 allocation_order.push_back(CGM->get_function(v));
432 for(
const auto& top_function : root_functions)
434 push_allocation_order(function_allocation_order[top_function], top_function);
436 for(
const auto& addr_func : CGM->GetAddressedFunctions())
438 const auto top_vertex = CGM->GetVertex(addr_func);
439 const auto subgraph = subgraph_from(top_vertex,
true);
440 cg[addr_func] = subgraph;
441 std::list<vertex> sorted;
442 subgraph->TopologicalSort(sorted);
443 for(
const auto& v : sorted)
445 const auto v_id = CGM->get_function(v);
446 if(!std::count_if(function_allocation_order.begin(), function_allocation_order.end(),
447 [&](
const std::pair<top_id_t, std::vector<func_id_t>>& p) {
448 return std::count(p.second.begin(), p.second.end(), v_id);
451 function_allocation_order[addr_func].push_back(v_id);
457 for(
const auto& f_order : function_allocation_order)
460 for(
const auto& f : f_order.second)
462 const auto fname =
HLSMgr->GetFunctionBehavior(f)->CGetBehavioralHelper()->get_function_name();
464 THROW_ASSERT(check_order.insert(f).second,
"Duplicate fuction in allocation order: " +
STR(f) +
" " + fname);
471 const auto compute_var_usage = [&](
const func_id_t f_id,
const top_id_t top_id) {
472 const auto function_behavior =
HLSMgr->CGetFunctionBehavior(f_id);
473 const auto BH = function_behavior->CGetBehavioralHelper();
477 const auto projection_in_degree = boost::in_degree(current_vertex, *cg.at(top_id));
479 if(projection_in_degree != 1)
481 if(cg_dominator_map.at(top_id).find(current_vertex) != cg_dominator_map.at(top_id).end())
488 vert_dominator.insert(current_vertex);
491 const auto& function_mem = function_behavior->get_function_mem();
492 for(
const auto v : function_mem)
494 if(function_behavior->is_a_state_variable(v))
496 var_map[top_id][v].insert(vert_dominator.begin(), vert_dominator.end());
500 var_map[top_id][v].insert(current_vertex);
502 where_used[top_id][v].insert(f_id);
504 "---Variable : " + BH->PrintVariable(v) +
" used in function " +
505 function_behavior->CGetBehavioralHelper()->get_function_name());
513 for(
const auto& top_order : function_allocation_order)
515 const auto& top_id = top_order.first;
517 "-->Analyzing top function: " +
518 HLSMgr->CGetFunctionBehavior(top_id)->CGetBehavioralHelper()->get_function_name());
519 for(
const auto& f_id : top_order.second)
521 compute_var_usage(f_id, top_id);
524 "<--Analyzed top function: " +
525 HLSMgr->CGetFunctionBehavior(top_id)->CGetBehavioralHelper()->get_function_name());
529 bool all_pointers_resolved =
true;
536 const auto function_behavior =
HLSMgr->CGetFunctionBehavior(fun_id);
537 const auto BH = function_behavior->CGetBehavioralHelper();
544 if(function_behavior->get_has_undefined_function_receiving_pointers())
547 "---Pointers not resolved: it has undefined function receiving pointers");
548 all_pointers_resolved =
false;
552 BOOST_FOREACH(
const vertex v, boost::vertices(*g))
554 const auto current_op = g->CGetOpNodeInfo(v)->GetOperation();
560 "---Pointers not resolved: it uses printf/builtin-wait-call/memset/memcpy/memcmp");
561 all_pointers_resolved =
false;
565 const auto curr_tn = TM->CGetTreeNode(g->CGetOpNodeInfo(v)->GetNodeId());
567 "-->Analyzing statement " +
GET_NAME(g, v) +
": " +
STR(curr_tn));
568 const auto me = GetPointer<const gimple_assign>(curr_tn);
569 THROW_ASSERT(me,
"only gimple_assign's are allowed as memory operations");
578 if(var && function_behavior->is_variable_mem(var->index))
580 res_set.insert(var->index);
585 "---Pointers not resolved: point-to-set not resolved");
586 all_pointers_resolved =
false;
596 if(var && function_behavior->is_variable_mem(var->index))
598 res_set.insert(var->index);
603 "---Pointers not resolved: point-to-set not resolved " + me->ToString());
604 all_pointers_resolved =
false;
608 for(
const auto& var : res_set)
612 "unexpected condition: " +
STR(TM->CGetTreeNode(var)) +
" is not a memory variable");
613 if(
HLSMgr->Rmem->has_sds_var(var) && !
HLSMgr->Rmem->is_sds_var(var))
618 THROW_ASSERT(g->CGetOpNodeInfo(v),
"unexpected condition");
619 const auto node_id = g->CGetOpNodeInfo(v)->GetNodeId();
620 const auto node = TM->CGetTreeNode(node_id);
621 const auto gm = GetPointer<const gimple_assign>(node);
622 THROW_ASSERT(gm,
"only gimple_assign's are allowed as memory operations");
623 unsigned long long value_bitsize;
624 unsigned long long alignment = 8ULL;
627 auto n_last_zerobits = 0u;
628 if(
GET_NODE(gm->op0)->get_kind() == mem_ref_K)
630 const auto mr = GetPointer<mem_ref>(
GET_NODE(gm->op0));
633 if(
GET_NODE(mr->op0)->get_kind() == ssa_name_K)
635 const auto ssa_addr = GetPointer<const ssa_name>(
GET_CONST_NODE(mr->op0));
637 "---STORE SSA pointer " + mr->op0->ToString() +
638 " bit_values=" + ssa_addr->bit_values);
639 if(ssa_addr->bit_values.find_first_not_of(
'0') == std::string::npos)
641 n_last_zerobits = 60;
645 for(
auto it = ssa_addr->bit_values.rbegin(); it != ssa_addr->bit_values.rend(); ++it)
647 if(*it ==
'0' || *it ==
'X')
668 alignment = (1ull << n_last_zerobits) * 8;
669 const auto var_read =
HLSMgr->get_required_values(fun_id, v);
670 const auto size_var = std::get<0>(var_read[0]);
673 const auto fd = GetPointer<const field_decl>(
GET_CONST_NODE(size_type));
674 if(!fd || !fd->is_bitfield())
676 value_bitsize =
std::max(8ull, value_bitsize);
678 HLSMgr->Rmem->add_source_value(var, size_var);
682 auto n_last_zerobits = 0u;
685 const auto mr = GetPointer<const mem_ref>(
GET_CONST_NODE(gm->op1));
690 const auto ssa_addr = GetPointer<const ssa_name>(
GET_CONST_NODE(mr->op0));
692 "---LOAD SSA pointer " + mr->op0->ToString() +
693 " bit_values=" + ssa_addr->bit_values);
694 if(ssa_addr->bit_values.find_first_not_of(
'0') == std::string::npos)
696 n_last_zerobits = 60;
700 for(
auto it = ssa_addr->bit_values.rbegin(); it != ssa_addr->bit_values.rend(); ++it)
702 if(*it ==
'0' || *it ==
'X')
723 alignment = (1ull << n_last_zerobits) * 8;
724 const auto size_var =
HLSMgr->get_produced_value(fun_id, v);
727 const auto fd = GetPointer<const field_decl>(
GET_CONST_NODE(size_type));
728 if(!fd || !fd->is_bitfield())
730 value_bitsize =
std::max(8ull, value_bitsize);
734 if(var_size.find(var) == var_size.end())
737 const auto is_a_struct_union =
746 if(unaligned_access_p)
748 if(assume_aligned_access_p)
750 THROW_ERROR(
"Option --aligned-access have been specified on a function with unaligned " 751 "accesses:\n\tVariable " +
752 BH->PrintVariable(var) +
" could be accessed in unaligned way");
754 HLSMgr->Rmem->set_sds_var(var,
false);
756 "---Variable " +
STR(var) +
" not sds because unaligned_access option specified");
758 else if(min_elmt_bitsize != elmt_bitsize || is_a_struct_union || elts_size != elmt_bitsize)
760 if(assume_aligned_access_p)
762 THROW_ERROR(
"Option --aligned-access have been specified on a function with unaligned " 763 "accesses:\n\tVariable " +
764 BH->PrintVariable(var) +
" could be accessed in unaligned way");
766 HLSMgr->Rmem->set_sds_var(var,
false);
768 "---Variable " +
STR(var) +
" not sds " +
STR(elmt_bitsize) +
" vs " +
769 STR(min_elmt_bitsize) +
" vs " +
STR(elts_size));
771 else if(value_bitsize != elmt_bitsize)
773 if(assume_aligned_access_p)
775 THROW_ERROR(
"Option --aligned-access have been specified on a function with unaligned " 776 "accesses:\n\tVariable " +
777 BH->PrintVariable(var) +
778 " could be accessed in unaligned way: " + curr_tn->ToString());
780 HLSMgr->Rmem->set_sds_var(var,
false);
782 "---Variable " +
STR(var) +
" not sds " +
STR(value_bitsize) +
" vs " +
785 else if(alignment < value_bitsize)
787 if(assume_aligned_access_p)
789 THROW_WARNING(
"Option --aligned-access have been specified on a function with not " 790 "compiler-proved unaligned accesses:\n\tVariable " +
791 BH->PrintVariable(var) +
" could be accessed in unaligned way");
796 HLSMgr->Rmem->set_sds_var(var,
false);
799 "---Variable " +
STR(var) +
" not sds because alignment=" +
STR(alignment) +
800 " is less than the value loaded or written or than the size of the array elements=" +
807 "---Variable " +
STR(var) +
" sds " +
STR(value_bitsize) +
" vs " +
809 HLSMgr->Rmem->set_sds_var(var,
true);
811 var_size[var] = value_bitsize;
815 if(var_size.at(var) != value_bitsize)
817 if(assume_aligned_access_p)
819 THROW_ERROR(
"Option --aligned-access have been specified on a function with unaligned " 820 "accesses:\n\tVariable " +
821 BH->PrintVariable(var) +
" could be accessed in unaligned way");
823 HLSMgr->Rmem->set_sds_var(var,
false);
825 "---Variable " +
STR(var) +
" not sds " +
STR(value_bitsize) +
" vs " +
826 STR(var_size.at(var)));
828 else if(alignment < value_bitsize)
830 if(assume_aligned_access_p)
832 THROW_WARNING(
"Option --aligned-access have been specified on a function with not " 833 "compiler-proved unaligned accesses:\n\tVariable " +
834 BH->PrintVariable(var) +
" could be accessed in unaligned way");
839 HLSMgr->Rmem->set_sds_var(var,
false);
841 "---Variable " +
STR(var) +
" not sds " +
STR(value_bitsize) +
" vs " +
842 STR(var_size.at(var)) +
" alignment=" +
STR(alignment) +
843 " value_bitsize2=" +
STR(var_size.at(var)));
849 "---Variable " +
STR(var) +
" sds " +
STR(value_bitsize));
853 var_referring_vertex_map[var][fun_id].insert(v);
856 var_load_vertex_map[var][fun_id].insert(v);
864 HLSMgr->Rmem->set_all_pointers_resolved(all_pointers_resolved);
866 if(all_pointers_resolved)
868 for(
const auto fun_id : func_list)
870 const auto function_behavior =
HLSMgr->CGetFunctionBehavior(fun_id);
871 const auto BH = function_behavior->CGetBehavioralHelper();
874 BOOST_FOREACH(
const vertex v, boost::vertices(*g))
879 const auto curr_tn = TM->CGetTreeNode(g->CGetOpNodeInfo(v)->GetNodeId());
880 const auto me = GetPointer<const gimple_assign>(curr_tn);
881 THROW_ASSERT(me,
"only gimple_assign's are allowed as memory operations");
896 used_set.insert(var->index);
899 if(used_set.size() > 1)
901 for(
const auto used_var : used_set)
904 "---Variable need the bus for loads and stores " + BH->PrintVariable(used_var));
905 HLSMgr->Rmem->add_need_bus(used_var);
919 for(
const auto root_function : root_functions)
921 num_instances[root_function][CGM->GetVertex(root_function)] = 1;
923 for(
const auto addr_function : CGM->GetAddressedFunctions())
925 num_instances[addr_function][CGM->GetVertex(addr_function)] = 1;
927 const auto compute_instances = [&](
const unsigned int f_id,
const unsigned int top_id) {
928 memory_allocation_map[top_id][f_id];
929 const auto top_cg = cg.at(top_id);
930 const auto f_v = CGM->GetVertex(f_id);
931 if(boost::out_degree(f_v, *top_cg))
934 "Missing HLS initialization for " +
935 HLSMgr->CGetFunctionBehavior(f_id)->CGetBehavioralHelper()->get_function_name());
936 const auto HLS_C =
HLSMgr->get_HLS(f_id)->HLS_C;
938 "missing number of instances of function " +
939 HLSMgr->CGetFunctionBehavior(f_id)->CGetBehavioralHelper()->get_function_name());
940 const auto cur_instances = num_instances.at(top_id).at(f_v);
945 if(
HLSMgr->Rfuns->is_a_proxied_function(tgt_fu_name) ||
946 (
parameters->getOption<
bool>(OPT_memory_mapped_top) &&
HLSMgr->hasToBeInterfaced(f_id)))
948 num_instances.at(top_id)[tgt] = 1;
950 else if(HLS_C->get_number_fu(tgt_fu_name,
WORK_LIBRARY) == 1)
952 num_instances.at(top_id)[tgt] = 1;
956 const auto n_call_points =
static_cast<unsigned int>(
957 Cget_edge_info<FunctionEdgeInfo, const CallGraph>(e, *top_cg)->direct_call_points.size());
958 if(!num_instances.at(top_id).count(tgt))
960 num_instances.at(top_id)[tgt] = cur_instances * n_call_points;
964 num_instances.at(top_id)[tgt] += cur_instances * n_call_points;
970 for(
const auto& f_order : function_allocation_order)
972 const auto top_id = f_order.first;
973 for(
const auto f_id : f_order.second)
975 compute_instances(f_id, top_id);
980 const auto no_private_mem =
982 const auto no_local_mem =
parameters->IsParameter(
"no-local-mem") &&
parameters->GetParameter<
bool>(
"no-local-mem");
984 for(
const auto& top_vars : var_map)
986 const auto& top_id = top_vars.first;
988 "-->Analyzing top function: " +
989 HLSMgr->CGetFunctionBehavior(top_id)->CGetBehavioralHelper()->get_function_name());
990 for(
const auto& var_uses : top_vars.second)
992 const auto& var_id = var_uses.first;
994 const auto& uses = var_uses.second;
996 "-->Finding common dominator for " +
STR(TM->CGetTreeReindex(var_id)) +
" (id: " +
STR(var_id) +
997 ", uses: " +
STR(uses.size()) +
")");
999 for(
const auto& reachable_vertex : reachable_vertices)
1001 for(
const auto use_vertex : uses)
1003 if(reachable_vertex.second.count(use_vertex))
1005 filtered_top_functions.insert(reachable_vertex.first);
1009 auto funID = top_id;
1010 bool multiple_top_call_graph =
false;
1013 if(filtered_top_functions.size() != 1)
1015 multiple_top_call_graph =
true;
1020 const auto is_written =
HLSMgr->get_written_objects().count(var_id) || no_private_mem;
1021 if(uses.size() == 1)
1023 auto cur = *uses.begin();
1025 "---Current function(0): " +
HLSMgr->CGetFunctionBehavior(CGM->get_function(cur))
1026 ->CGetBehavioralHelper()
1027 ->get_function_name());
1028 const auto fun_behavior =
HLSMgr->CGetFunctionBehavior(CGM->get_function(cur));
1030 if(is_written && fun_behavior->is_a_state_variable(var_id))
1032 while(num_instances.at(top_id).at(cur) != 1)
1036 "---Current function(1): " +
HLSMgr->CGetFunctionBehavior(CGM->get_function(cur))
1037 ->CGetBehavioralHelper()
1038 ->get_function_name());
1041 funID = CGM->get_function(cur);
1045 if(filtered_top_functions.size() != 1)
1047 multiple_top_call_graph =
true;
1051 const auto top_vertex = CGM->GetVertex(top_id);
1052 const auto vert_it_end = uses.end();
1053 auto vert_it = uses.begin();
1054 std::list<vertex> dominator_list1;
1055 auto cur = *vert_it;
1057 "---Current function(2a): " +
HLSMgr->CGetFunctionBehavior(CGM->get_function(cur))
1058 ->CGetBehavioralHelper()
1059 ->get_function_name());
1060 dominator_list1.push_front(cur);
1065 "---Current function(2b): " +
HLSMgr->CGetFunctionBehavior(CGM->get_function(cur))
1066 ->CGetBehavioralHelper()
1067 ->get_function_name());
1068 dominator_list1.push_front(cur);
1069 }
while(cur != top_vertex);
1071 auto last = dominator_list1.end();
1072 for(; vert_it != vert_it_end; ++vert_it)
1074 std::list<vertex> dominator_list2;
1077 "---Current function(2c): " +
HLSMgr->CGetFunctionBehavior(CGM->get_function(cur))
1078 ->CGetBehavioralHelper()
1079 ->get_function_name());
1080 dominator_list2.push_front(cur);
1085 "---Current function(2d): " +
1086 HLSMgr->CGetFunctionBehavior(CGM->get_function(cur))
1087 ->CGetBehavioralHelper()
1088 ->get_function_name());
1089 dominator_list2.push_front(cur);
1090 }
while(cur != top_vertex);
1092 auto dl1_it = dominator_list1.begin(), dl2_it = dominator_list2.begin(),
1093 dl2_it_end = dominator_list2.end(), cur_last = dominator_list1.begin();
1094 while(dl1_it != last && dl2_it != dl2_it_end && *dl1_it == *dl2_it &&
1095 (num_instances.at(top_id).at(*dl1_it) == 1 || !is_written))
1099 "---Current function(2e): " +
1100 HLSMgr->CGetFunctionBehavior(CGM->get_function(cur))
1101 ->CGetBehavioralHelper()
1102 ->get_function_name() +
1103 " num instances: " +
STR(num_instances.at(top_id).at(cur)));
1109 funID = CGM->get_function(cur);
1110 if(cur == top_vertex)
1118 THROW_ASSERT(funID,
"null function id index unexpected");
1119 const auto is_internal =
is_internal_obj(var_id, funID, multiple_top_call_graph);
1120 memory_allocation_map.at(top_id)[funID].push_back(std::make_pair(var_id, is_internal));
1122 "<--Found common dominator for " +
1123 HLSMgr->CGetFunctionBehavior(funID)->CGetBehavioralHelper()->get_function_name() +
" -> " +
1124 STR(TM->CGetTreeReindex(var_id)) +
" (scope: " + (is_internal ?
"internal" :
"external") +
1128 "<--Analyzed top function: " +
1129 HLSMgr->CGetFunctionBehavior(top_id)->CGetBehavioralHelper()->get_function_name());
1133 const auto classify_variables = [&](
const func_id_t f_id,
const top_id_t top_id) {
1134 const auto it = memory_allocation_map.at(top_id).find(f_id);
1135 if(it != memory_allocation_map.at(top_id).end())
1137 for(
const auto& mem_map : it->second)
1139 const auto var_id = mem_map.first;
1141 const auto is_internal = mem_map.second;
1142 auto is_dynamic_address_used =
false;
1146 THROW_ASSERT(where_used.at(top_id)[var_id].size() > 0,
"variable not used anywhere");
1148 const auto wiu_it_end = where_used.at(top_id).at(var_id).end();
1149 for(
auto wiu_it = where_used.at(top_id).at(var_id).begin();
1150 wiu_it != wiu_it_end && !is_dynamic_address_used; ++wiu_it)
1152 const auto cur_function_behavior =
HLSMgr->CGetFunctionBehavior(*wiu_it);
1153 if(cur_function_behavior->get_dynamic_address().find(var_id) !=
1154 cur_function_behavior->get_dynamic_address().end() ||
1155 (GetPointer<const var_decl>(TM->CGetTreeNode(var_id)) &&
1156 GetPointerS<const var_decl>(TM->CGetTreeNode(var_id))->addr_taken))
1159 "---Found dynamic use of variable: " +
1160 cur_function_behavior->CGetBehavioralHelper()->PrintVariable(var_id) +
" - " +
1161 STR(var_id) +
" - " +
1162 HLSMgr->CGetFunctionBehavior(*(where_used.at(top_id).at(var_id).begin()))
1163 ->CGetBehavioralHelper()
1164 ->PrintVariable(var_id) +
1166 cur_function_behavior->CGetBehavioralHelper()->get_function_name());
1167 is_dynamic_address_used =
true;
1171 if(is_dynamic_address_used && !all_pointers_resolved && !assume_aligned_access_p)
1173 HLSMgr->Rmem->set_sds_var(var_id,
false);
1177 if(!
HLSMgr->Rmem->has_sds_var(var_id) && assume_aligned_access_p)
1179 HLSMgr->Rmem->set_sds_var(var_id,
true);
1181 else if(!
HLSMgr->Rmem->has_sds_var(var_id))
1183 HLSMgr->Rmem->set_sds_var(var_id,
false);
1187 if(!no_private_mem && !no_local_mem)
1189 if(!is_dynamic_address_used &&
1190 HLSMgr->get_written_objects().find(var_id) ==
1191 HLSMgr->get_written_objects().end()
1194 if(!GetPointer<const gimple_call>(TM->CGetTreeNode(var_id)))
1196 HLSMgr->Rmem->add_private_memory(var_id);
1199 else if(CGM->ExistsAddressedFunction())
1201 if(var_map.at(top_id).at(var_id).size() == 1 && where_used.at(top_id).at(var_id).size() == 1 &&
1202 !is_dynamic_address_used &&
1203 (*(where_used.at(top_id).at(var_id).begin()) == f_id) &&
1204 !GetPointer<const gimple_call>(TM->CGetTreeNode(var_id)))
1206 HLSMgr->Rmem->add_private_memory(var_id);
1211 if(!is_dynamic_address_used &&
1212 !GetPointer<const gimple_call>(TM->CGetTreeNode(var_id)))
1214 HLSMgr->Rmem->add_private_memory(var_id);
1221 is_dynamic_address_used =
true;
1222 if(assume_aligned_access_p)
1224 HLSMgr->Rmem->set_sds_var(var_id,
true);
1228 HLSMgr->Rmem->set_sds_var(var_id,
false);
1232 const auto vd = GetPointer<const var_decl>(TM->CGetTreeNode(var_id));
1233 if((
HLSMgr->get_written_objects().find(var_id) ==
HLSMgr->get_written_objects().end()) &&
1234 (!is_dynamic_address_used || (vd && vd->readonly_flag)))
1236 HLSMgr->Rmem->add_read_only_variable(var_id);
1244 for(
const auto& top_order : function_allocation_order)
1246 const auto& top_id = top_order.first;
1247 if(memory_allocation_map.find(top_id) != memory_allocation_map.end())
1249 for(
const auto& f_id : top_order.second)
1251 classify_variables(f_id, top_id);
1261 auto max_byte_size =
HLSMgr->Rmem->get_internal_base_address_alignment();
1262 for(
const auto& mem_map : memory_allocation_map)
1264 for(
const auto& f_pair : mem_map.second)
1266 for(
const auto& pair : f_pair.second)
1268 const auto& var_id = pair.first;
1270 if(pair.second && (!
HLSMgr->Rmem->is_private_memory(var_id) || null_pointer_check))
1273 max_byte_size =
std::max(static_cast<unsigned long long>(curr_size), max_byte_size);
1279 max_byte_size = ceil_pow2(max_byte_size);
1280 HLSMgr->Rmem->set_internal_base_address_alignment(max_byte_size);
1282 "Sparse memory alignemnt set to " +
STR(max_byte_size) +
" bytes");
1285 const auto memory_mapped_top_if =
parameters->getOption<
bool>(OPT_memory_mapped_top);
1286 const auto allocate_function_mem = [&](
const func_id_t f_id,
const top_id_t top_id,
const memoryRef& Rmem) {
1291 THROW_ASSERT(memory_allocation_map.count(top_id),
"Invalid top function id.");
1292 const auto func_mem_map = memory_allocation_map.at(top_id).find(f_id);
1293 if(func_mem_map != memory_allocation_map.at(top_id).end())
1295 for(
const auto& mem_map : func_mem_map->second)
1297 const auto var_id = mem_map.first;
1299 const auto var_node = TM->CGetTreeReindex(var_id);
1300 const auto is_internal = mem_map.second;
1301 auto is_dynamic_address_used =
false;
1305 THROW_ASSERT(where_used.at(top_id)[var_id].size() > 0,
"variable not used anywhere");
1306 const auto function_behavior =
HLSMgr->CGetFunctionBehavior(*(where_used.at(top_id).at(var_id).begin()));
1307 const auto BH = function_behavior->CGetBehavioralHelper();
1308 const auto var_id_string = BH->PrintVariable(var_id);
1311 const auto wiu_it_end = where_used.at(top_id).at(var_id).end();
1312 for(
auto wiu_it = where_used.at(top_id).at(var_id).begin();
1313 wiu_it != wiu_it_end && !is_dynamic_address_used; ++wiu_it)
1315 const auto cur_function_behavior =
HLSMgr->CGetFunctionBehavior(*wiu_it);
1317 "---Analyzing function " +
1318 cur_function_behavior->CGetBehavioralHelper()->get_function_name());
1319 if(cur_function_behavior->get_dynamic_address().count(var_id) ||
1321 GetPointerS<const var_decl>(
GET_CONST_NODE(var_node))->addr_taken))
1324 "---Found dynamic use of variable: " +
1325 cur_function_behavior->CGetBehavioralHelper()->PrintVariable(var_id) +
" - " +
1326 STR(var_id) +
" - " + var_id_string +
" in function " +
1327 cur_function_behavior->CGetBehavioralHelper()->get_function_name());
1328 is_dynamic_address_used =
true;
1332 if(!is_dynamic_address_used &&
1333 !
HLSMgr->get_written_objects().count(var_id)
1334 && (!no_private_mem && !no_local_mem))
1336 for(
auto wiu_it = where_used.at(top_id).at(var_id).begin(); wiu_it != wiu_it_end; ++wiu_it)
1338 const auto cur_function_behavior =
HLSMgr->CGetFunctionBehavior(*wiu_it);
1339 const auto cur_BH = cur_function_behavior->CGetBehavioralHelper();
1341 "---Internal variable: " + cur_BH->PrintVariable(var_id) +
" - " +
STR(var_id) +
1342 " - " + var_id_string +
" in function " + cur_BH->get_function_name());
1343 Rmem->add_internal_variable(*wiu_it, var_id, cur_BH->PrintVariable(var_id));
1347 else if(CGM->ExistsAddressedFunction())
1349 const auto cur_function_behavior =
HLSMgr->CGetFunctionBehavior(f_id);
1350 const auto cur_BH = cur_function_behavior->CGetBehavioralHelper();
1352 "-->Internal variable: " + cur_BH->PrintVariable(var_id) +
" - " +
STR(var_id) +
1353 " - " + var_id_string +
" in function " + cur_BH->get_function_name());
1354 Rmem->add_internal_variable(f_id, var_id, cur_BH->PrintVariable(var_id));
1358 const auto cur_function_behavior =
HLSMgr->CGetFunctionBehavior(f_id);
1359 const auto cur_BH = cur_function_behavior->CGetBehavioralHelper();
1361 "-->Internal variable: " + cur_BH->PrintVariable(var_id) +
" - " +
STR(var_id) +
1362 " - " + var_id_string +
" in function " + cur_BH->get_function_name());
1363 Rmem->add_internal_variable(f_id, var_id, cur_BH->PrintVariable(var_id));
1365 if(!no_private_mem && !no_local_mem)
1367 for(
const auto& wu_id : where_used.at(top_id)[var_id])
1371 Rmem->add_internal_variable_proxy(wu_id, var_id);
1379 const auto function_behavior =
HLSMgr->CGetFunctionBehavior(f_id);
1380 const auto BH = function_behavior->CGetBehavioralHelper();
1381 const auto var_id_string = BH->PrintVariable(var_id);
1383 "-->Variable external to the top module: " + BH->PrintVariable(var_id) +
" - " +
1384 STR(var_id) +
" - " + var_id_string);
1385 Rmem->add_external_variable(var_id, BH->PrintVariable(var_id));
1386 is_dynamic_address_used =
true;
1388 const auto is_packed =
1390 Rmem->set_packed_vars(is_packed);
1394 "---Base Address: " +
STR(Rmem->get_base_address(var_id, f_id)));
1397 if(
HLSMgr->Rmem->is_private_memory(var_id))
1401 if(
HLSMgr->Rmem->is_a_proxied_variable(var_id))
1405 if(
HLSMgr->Rmem->is_read_only_variable(var_id))
1409 if(
HLSMgr->Rmem->is_parm_decl_copied(var_id))
1413 if(
HLSMgr->Rmem->is_actual_parm_loaded(var_id))
1417 if(
HLSMgr->Rmem->is_parm_decl_stored(var_id))
1421 if(is_dynamic_address_used)
1425 if(
HLSMgr->Rmem->is_sds_var(var_id))
1428 "---The variable is always accessed with the same data size");
1429 const auto vd = GetPointer<const var_decl>(
GET_CONST_NODE(var_node));
1430 if(vd && vd->bit_values.size() != 0)
1433 "---The variable has been trimmed to bitsize: " +
STR(vd->bit_values.size()) +
1434 " with bit-value pattern: " + vd->bit_values);
1437 if(var_referring_vertex_map.count(var_id))
1440 "---Number of functions in which is used: " +
1441 STR(var_referring_vertex_map.at(var_id).size()));
1442 size_t max_references = 0;
1443 for(
const auto& fun_vertex_set : var_referring_vertex_map.at(var_id))
1445 max_references = max_references >
static_cast<size_t>(fun_vertex_set.second.size()) ?
1447 static_cast<size_t>(fun_vertex_set.second.size());
1449 Rmem->set_maximum_references(var_id, max_references);
1451 "---Maximum number of references per function: " +
STR(max_references));
1453 if(var_load_vertex_map.count(var_id))
1455 size_t max_loads = 0;
1456 for(
const auto& fun_vertex_set : var_load_vertex_map.at(var_id))
1458 max_loads = max_loads >
static_cast<size_t>(fun_vertex_set.second.size()) ?
1460 static_cast<size_t>(fun_vertex_set.second.size());
1462 Rmem->set_maximum_loads(var_id, max_loads);
1464 "---Maximum number of loads per function: " +
STR(max_loads));
1473 if(f_id && (top_functions.count(f_id) ? memory_mapped_top_if :
HLSMgr->hasToBeInterfaced(f_id)))
1482 "Internal memory address base: " +
STR(
HLSMgr->Rmem->get_next_internal_base_address()));
1484 for(
const auto& top_order : function_allocation_order)
1486 const auto& top_id = top_order.first;
1487 if(memory_allocation_map.find(top_id) != memory_allocation_map.end())
1489 for(
const auto& f_id : top_order.second)
1491 allocate_function_mem(f_id, top_id,
HLSMgr->Rmem);
1506 "---Time to perform memory allocation: " +
print_cpu_time(step_time) +
" seconds");
1509 const auto changed =
HLSMgr->Rmem->notEQ(prevRmem);
1512 HLSMgr->UpdateMemVersion();
1514 const auto TechM = HLS_D->get_technology_manager();
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
static bool IsUnionType(const tree_nodeConstRef &type)
Return if treenode is an union.
const HLS_managerRef HLSMgr
information about all the HLS synthesis
static bool IsComplexType(const tree_nodeConstRef &type)
Return if treenode is a complex.
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;.
#define GET_TYPE(data, vertex_index)
Helper macro returning the type associated with a node.
#define MEMCPY
constant string identifying the operation performed when two objects are memcopied.
static unsigned long long AccessedMaximumBitsize(const tree_nodeConstRef &type_node, unsigned long long bitsize)
return the maximum bitsize associated with the elements accessible through type_node ...
Dominator o post-dominator data structure.
DesignFlowStep_Status InternalExec() override
Execute the step.
#define OUTPUT_LEVEL_NONE
no output print is performed.
Step successfully executed.
#define GET_CLASS(obj)
Macro returning the actual type of an object.
const int output_level
The output level.
static bool IsArrayEquivType(const tree_nodeConstRef &type)
Return true if treenode is an array or it is equivalent to an array (record recursively having a sing...
mathematical utility function not provided by standard libraries
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
all objects that need to be stored in memory are allocated on an external pipelined memory ...
void finalize_memory_allocation()
Performs a final analysis of the memory allocation to finalize the data-structure.
virtual bool is_internal_obj(unsigned int var_id, unsigned int fun_id, bool multiple_top_call_graph)
function checking if the current variable has to allocated inside the accelerator or outside ...
#define GET_NAME(data, vertex_index)
Helper macro returning the name associated with a node.
CustomOrderedMap< T, U > CustomMap
#define BUILTIN_WAIT_CALL
constant defining the builtin wait call intrinsic function
static unsigned long long GetArrayElementSize(const tree_nodeConstRef &node)
Return the size (in bits) of the base element of the array.
#define CE_XVM(variable, node)
Check existence XML Value Macro. Check if an XML attribute is present in the XML tree.
Class specification of the manager of the technology library data structures.
all objects that need to be stored in memory are allocated on an external memory
#define OUTPUT_LEVEL_MINIMUM
minimum debugging print is performed.
redefinition of map to manage ordered/unordered structures
Include a set of utilities used to manage CPU time measures.
#define TYPE_LOAD
Constant string identifying a memory load operation.
#define THROW_WARNING(str_expr)
helper function used to throw a warning in a standard way: though it uses PRINT_DBG_MEX, the debug level used is such that the message is always printed
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
std::map< std::string, std::set< std::string > > user_internal_objects
#define MEMSET
constant string identifying the operation performed when two objects are memsetted.
void Initialize() override
Initialize the step (i.e., like a constructor, but executed just before exec.
#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
static unsigned long long AccessedMinimunBitsize(const tree_nodeConstRef &type_node, unsigned long long bitsize)
return the minimum bitsize associated with the elements accessible through type_node ...
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
~mem_dominator_allocation() override
Destructor.
Class to allocate memories in HLS based on dominators.
static memoryRef create_memory(const ParameterConstRef _parameters, const tree_managerConstRef _TreeM, unsigned long long int _off_base_address, unsigned int max_bram, bool _null_pointer_check, bool initial_internal_address_p, unsigned int initial_internal_address, const unsigned int &_address_bitsize)
all global variables, static variables and strings are allocated on BRAMs
Class specification of the data structures used to manage technology information. ...
redefinition of set to manage ordered/unordered structures
#define STOP_TIME(time_var)
Macro used to store the elapsed time into time_var.
Datastructure to describe functions allocation in high-level synthesis.
#define TYPE_STORE
Constant string identifying a memory store operation.
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
void allocate_parameters(unsigned int functionId, memoryRef Rmem=nullptr)
Allocate parameters for given function.
#define MEMCMP
constant string identifying the operation performed when two objects are memcompared.
static std::string GetFUName(const std::string &fname, const HLS_managerRef HLSMgr)
Return FU used to implement given function.
#define GET_CONST_NODE(t)
Classes specification of the tree_node data structures.
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
#define DEBUG_LEVEL_NONE
no debugging print is performed.
void Exec()
Parse an XML document from a file.
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Data structure definition for HLS constraints.
T compute_n_bytes(T bitsize)
This file collects some utility functions.
static vertex get_remapped_vertex(vertex current_vertex, const CallGraphManagerConstRef CG, const HLS_managerRef HLSMgr)
check if current_vertex is a proxied function
std::string print_cpu_time(long int t)
massage a long which represents a time interval in milliseconds, into a string suitable for output ...
std::map< _Key, _Tp, _Compare, _Alloc > OrderedMapStd
static bool IsPackedType(const tree_nodeConstRef &type)
static tree_nodeConstRef GetBaseVariable(const tree_nodeConstRef &mem)
Retrun the base variable of a memory access.
CustomOrderedSet< unsigned int > func_list
list of functions to be analyzed
#define OUTPUT_LEVEL_PEDANTIC
verbose debugging print is performed.
struct definition of the type node structures.
Class specification of the tree_reindex support class.
#define WORK_LIBRARY
working library.
all local variables, static variables and strings are allocated on BRAMs
Data structures used in operations graph.
std::map< std::string, std::set< std::string > > user_external_objects
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
static tree_nodeConstRef CGetType(const tree_nodeConstRef &node)
Return the treenode of the type of node.
xml_documentRef get_document()
Obtain the parsed document.
static bool IsStructType(const tree_nodeConstRef &type)
Return true if treenode is a record.
this class is used to manage the command-line or XML options.
#define LOAD_XVM(variable, node)
LOAD XML Value Macro. Set a variable starting from an XML value. Conversion is performed if needed...
mem_dominator_allocation(const ParameterConstRef _parameters, const HLS_managerRef HLSMgr, const DesignFlowManagerConstRef design_flow_manager, const HLSFlowStepSpecializationConstRef hls_flow_step_specialization, const HLSFlowStep_Type hls_flow_step_type=HLSFlowStep_Type::DOMINATOR_MEMORY_ALLOCATION)
Constructor.
Some macro used to interface with the XML library.
Generic device description.
static integer_cst_t GetConstValue(const tree_nodeConstRef &tn, bool is_signed=true)
Get value from integer constant.
int debug_level
The debug level.
#define OUTPUT_LEVEL_VERBOSE
verbose debugging print is performed.
all objects that need to be stored in memory are allocated on BRAMs
unsigned long long int user_defined_base_address
user defined base address
#define DEBUG_LEVEL_VERBOSE
verbose debugging print is performed.
static bool IsPointerResolved(const tree_nodeConstRef &ptr, CustomOrderedSet< unsigned int > &res_set)
Data structure definition for high-level synthesis flow.
#define NULL_VERTEX
null vertex definition
Datastructure to represent memory information in high-level synthesis.
#define PROXY_LIBRARY
proxy library
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.
void setup_memory_allocation()
Prepares the data structures for the memory allocation.
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 ...