PandA-2024.02
memory_allocation.cpp
Go to the documentation of this file.
1 /*
2  *
3  * _/_/_/ _/_/ _/ _/ _/_/_/ _/_/
4  * _/ _/ _/ _/ _/_/ _/ _/ _/ _/ _/
5  * _/_/_/ _/_/_/_/ _/ _/_/ _/ _/ _/_/_/_/
6  * _/ _/ _/ _/ _/ _/ _/ _/ _/
7  * _/ _/ _/ _/ _/ _/_/_/ _/ _/
8  *
9  * ***********************************************
10  * PandA Project
11  * URL: http://panda.dei.polimi.it
12  * Politecnico di Milano - DEIB
13  * System Architectures Group
14  * ***********************************************
15  * Copyright (C) 2004-2024 Politecnico di Milano
16  *
17  * This file is part of the PandA framework.
18  *
19  * The PandA framework is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 3 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program. If not, see <http://www.gnu.org/licenses/>.
31  *
32  */
44 #include "memory_allocation.hpp"
45 
46 #include "Parameter.hpp"
47 #include "application_manager.hpp"
48 #include "behavioral_helper.hpp"
49 #include "call_graph.hpp"
50 #include "call_graph_manager.hpp"
51 #include "custom_map.hpp"
52 #include "custom_set.hpp"
53 #include "dbgPrintHelper.hpp"
54 #include "ext_tree_node.hpp"
55 #include "function_behavior.hpp"
56 #include "generic_device.hpp"
57 #include "hls_device.hpp"
58 #include "hls_manager.hpp"
59 #include "math_function.hpp"
60 #include "memory.hpp"
61 #include "op_graph.hpp"
62 #include "string_manipulation.hpp"
63 #include "tree_helper.hpp"
64 #include "tree_manager.hpp"
65 #include "tree_node.hpp"
66 #include "tree_reindex.hpp"
67 
68 #include <algorithm>
69 #include <string>
70 #include <tuple>
71 #include <vector>
72 
74  const MemoryAllocation_Policy _memory_allocation_policy,
75  const MemoryAllocation_ChannelsType _memory_allocation_channels_type)
76  : memory_allocation_policy(_memory_allocation_policy),
77  memory_allocation_channels_type(_memory_allocation_channels_type)
78 {
79 }
80 
82 {
83  std::string ret;
85  {
87  ret += "LSS";
88  break;
90  ret += "GSS";
91  break;
93  ret += "ALL_BRAM";
94  break;
96  ret += "NO_BRAM";
97  break;
99  ret += "EXT_PIPELINED_BRAM";
100  break;
102  default:
103  THROW_UNREACHABLE("");
104  }
105  ret += "-";
107  {
109  ret += "11";
110  break;
112  ret += "N1";
113  break;
115  ret += "NN";
116  break;
118  ret += "P1N";
119  break;
121  ret += "CS";
122  break;
123  default:
124  THROW_UNREACHABLE("");
125  }
126  return ret;
127 }
128 
130 {
131  return STR(static_cast<unsigned int>(memory_allocation_policy)) +
132  "::" + STR(static_cast<unsigned int>(memory_allocation_channels_type));
133 }
134 
136  const DesignFlowManagerConstRef _design_flow_manager,
137  const HLSFlowStep_Type _hls_flow_step_type,
138  const HLSFlowStepSpecializationConstRef _hls_flow_step_specialization)
139  : HLS_step(_parameters, _HLSMgr, _design_flow_manager, _hls_flow_step_type,
140  _hls_flow_step_specialization and
141  GetPointer<const MemoryAllocationSpecialization>(_hls_flow_step_specialization) ?
142  _hls_flow_step_specialization :
144  _parameters->getOption<MemoryAllocation_Policy>(OPT_memory_allocation_policy),
145  _parameters->getOption<MemoryAllocation_ChannelsType>(OPT_channels_type)))),
147  memory_version(0)
148 {
149  debug_level = parameters->get_class_debug_level(GET_CLASS(*this));
150 }
151 
153 
156 {
158  switch(relationship_type)
159  {
161  {
164  ret.insert(std::make_tuple(parameters->getOption<HLSFlowStep_Type>(OPT_function_allocation_algorithm),
166  break;
167  }
169  {
170  break;
171  }
173  {
174  break;
175  }
176  default:
177  THROW_UNREACHABLE("");
178  }
179  return ret;
180 }
181 
183 {
184  const auto cg_man = HLSMgr->CGetCallGraphManager();
185  func_list = cg_man->GetReachedBodyFunctions();
187  for(const auto It : func_list)
188  {
189  const auto function_behavior = HLSMgr->CGetFunctionBehavior(It);
191  const auto& parm_decl_copied = function_behavior->get_parm_decl_copied();
192  for(const auto p : parm_decl_copied)
193  {
194  HLSMgr->Rmem->add_parm_decl_copied(p);
195  }
197  const auto& parm_decl_stored = function_behavior->get_parm_decl_stored();
198  for(const auto p : parm_decl_stored)
199  {
200  HLSMgr->Rmem->add_parm_decl_stored(p);
201  }
203  const auto& parm_decl_loaded = function_behavior->get_parm_decl_loaded();
204  for(const auto p : parm_decl_loaded)
205  {
206  HLSMgr->Rmem->add_actual_parm_loaded(p);
207  }
208  }
209 }
210 
212 {
213  THROW_ASSERT(func_list.size(), "Empty list of functions to be analyzed");
214  bool use_unknown_address = false;
215  bool has_unaligned_accesses = false;
216  auto m64P = parameters->getOption<std::string>(OPT_gcc_m32_mx32).find("-m64") != std::string::npos;
217  bool assume_aligned_access_p =
218  parameters->isOption(OPT_aligned_access) && parameters->getOption<bool>(OPT_aligned_access);
219  const auto TreeM = HLSMgr->get_tree_manager();
220  for(const auto It : func_list)
221  {
222  const auto FB = HLSMgr->CGetFunctionBehavior(It);
223  const auto BH = FB->CGetBehavioralHelper();
224  const auto& function_parameters = BH->get_parameters();
225 
226  if(FB->get_dereference_unknown_addr())
227  {
229  "---This function uses unknown addresses deref: " + BH->get_function_name());
230  }
231 
232  use_unknown_address |= FB->get_dereference_unknown_addr();
233 
234  if(FB->get_unaligned_accesses())
235  {
237  "---This function performs unaligned accesses: " + BH->get_function_name());
238  if(assume_aligned_access_p)
239  {
240  THROW_ERROR("Option --aligned-access have been specified on a function with unaligned accesses");
241  }
242  }
243 
244  has_unaligned_accesses |= FB->get_unaligned_accesses();
245 
246  for(auto const parameter : function_parameters)
247  {
248  if(HLSMgr->Rmem->is_parm_decl_copied(parameter) && !HLSMgr->Rmem->is_parm_decl_stored(parameter))
249  {
250  HLSMgr->Rmem->set_implicit_memcpy(true);
251  }
252  }
253  }
254 
255  if(HLSMgr->Rmem->has_implicit_memcpy())
256  {
257  const auto memcpy_function = TreeM->GetFunction(MEMCPY);
258  func_list.insert(memcpy_function->index);
259  }
260 
261  unsigned long long maximum_bus_size = 0;
262  bool use_databus_width = false;
263  bool has_intern_shared_data = false;
264  bool has_misaligned_indirect_ref = HLSMgr->Rmem->has_packed_vars();
265  bool needMemoryMappedRegisters = false;
266  const auto call_graph_manager = HLSMgr->CGetCallGraphManager();
267  const auto root_functions = call_graph_manager->GetRootFunctions();
269  for(auto fun_id : func_list)
270  {
271  const auto function_behavior = HLSMgr->CGetFunctionBehavior(fun_id);
272  const auto behavioral_helper = function_behavior->CGetBehavioralHelper();
273  const auto is_interfaced = HLSMgr->hasToBeInterfaced(behavioral_helper->get_function_index());
274  const auto fname = behavioral_helper->GetMangledFunctionName();
275  const auto func_arch = HLSMgr->module_arch->GetArchitecture(fname);
276  if(function_behavior->get_has_globals() && parameters->isOption(OPT_expose_globals) &&
277  parameters->getOption<bool>(OPT_expose_globals))
278  {
279  has_intern_shared_data = true;
280  }
281  const auto& function_parameters = behavioral_helper->get_parameters();
282  for(const auto function_parameter : function_parameters)
283  {
284  const auto pname = behavioral_helper->PrintVariable(function_parameter);
285  if(func_arch && root_functions.find(fun_id) != root_functions.end())
286  {
287  THROW_ASSERT(func_arch->parms.find(pname) != func_arch->parms.end(),
288  "Parameter " + pname + " not found in function " + fname);
289  const auto& parm_attrs = func_arch->parms.at(pname);
290  const auto& iface_attrs = func_arch->ifaces.at(parm_attrs.at(FunctionArchitecture::parm_bundle));
291  const auto iface_mode = iface_attrs.at(FunctionArchitecture::iface_mode);
292  if(iface_mode != "default")
293  {
294  continue;
295  }
296  }
297  if(HLSMgr->Rmem->is_parm_decl_copied(function_parameter) &&
298  !HLSMgr->Rmem->is_parm_decl_stored(function_parameter))
299  {
300  use_databus_width = true;
301  maximum_bus_size = std::max(maximum_bus_size, 8ull);
302  }
303  if(!use_unknown_address && is_interfaced && tree_helper::is_a_pointer(TreeM, function_parameter))
304  {
305  use_unknown_address = true;
307  {
308  THROW_WARNING("This function uses unknown addresses: " + behavioral_helper->get_function_name());
309  }
310  }
311  }
312  if(function_behavior->has_packed_vars())
313  {
314  has_misaligned_indirect_ref = true;
315  }
316  const auto& parm_decl_stored = function_behavior->get_parm_decl_stored();
317  for(unsigned int p : parm_decl_stored)
318  {
319  maximum_bus_size =
320  std::max(maximum_bus_size, tree_helper::Size(tree_helper::CGetType(TreeM->CGetTreeReindex(p))));
321  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "param with maximum_bus_size=" + STR(maximum_bus_size));
322  }
324  "Analyzing function for bus size: " + behavioral_helper->get_function_name());
325  const auto g = function_behavior->CGetOpGraph(FunctionBehavior::CFG);
326  graph::vertex_iterator v, v_end;
327  const auto TM = HLSMgr->get_tree_manager();
328  const auto fnode = TM->CGetTreeReindex(fun_id);
330  if(HLSMgr->design_interface_io.find(fname) != HLSMgr->design_interface_io.end())
331  {
332  for(const auto& bb2arg2stmtsR : HLSMgr->design_interface_io.find(fname)->second)
333  {
334  for(const auto& arg2stms : bb2arg2stmtsR.second)
335  {
336  if(arg2stms.second.size() > 0)
337  {
338  for(const auto& stmt : arg2stms.second)
339  {
340  const auto op_it = g->CGetOpGraphInfo()->tree_node_to_operation.find(stmt);
341  if(op_it != g->CGetOpGraphInfo()->tree_node_to_operation.end())
342  {
343  RW_stmts.insert(op_it->second);
344  }
345  }
346  }
347  }
348  }
349  }
350 
351  for(boost::tie(v, v_end) = boost::vertices(*g); v != v_end; ++v)
352  {
353  if(RW_stmts.find(*v) != RW_stmts.end())
354  {
355  continue;
356  }
357  const auto current_op = g->CGetOpNodeInfo(*v)->GetOperation();
358  const auto var_read = HLSMgr->get_required_values(fun_id, *v);
359  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Analyzing operation " + GET_NAME(g, *v));
360  if(GET_TYPE(g, *v) & (TYPE_LOAD | TYPE_STORE))
361  {
362  const auto curr_tn = TreeM->CGetTreeNode(g->CGetOpNodeInfo(*v)->GetNodeId());
363  const auto me = GetPointer<const gimple_assign>(curr_tn);
364  THROW_ASSERT(me, "only gimple_assign's are allowed as memory operations");
365  tree_nodeRef expr;
366  if(GET_TYPE(g, *v) | TYPE_STORE)
367  {
368  expr = me->op0;
369  }
370  else
371  {
372  expr = me->op1;
373  }
374  const auto var = tree_helper::GetBaseVariable(expr);
376  {
377  has_misaligned_indirect_ref = true;
378  }
380  if(!has_misaligned_indirect_ref)
381  {
382  has_misaligned_indirect_ref = tree_helper::is_packed_access(TreeM, expr->index);
383  }
384 
386  if(!has_intern_shared_data && var && function_behavior->is_variable_mem(var->index) &&
387  !HLSMgr->Rmem->is_private_memory(var->index) && parameters->isOption(OPT_expose_globals) &&
388  parameters->getOption<bool>(OPT_expose_globals))
389  {
390  const auto vd = GetPointer<const var_decl>(GET_CONST_NODE(var));
391  if(vd &&
392  (((!vd->scpe || GET_NODE(vd->scpe)->get_kind() == translation_unit_decl_K) && !vd->static_flag) ||
393  tree_helper::IsVolatile(var) || call_graph_manager->ExistsAddressedFunction()))
394  {
395  has_intern_shared_data =
396  true;
397  }
398  }
399  unsigned long long value_bitsize;
400  if(GET_TYPE(g, *v) & TYPE_STORE)
401  {
402  const auto size_var = std::get<0>(var_read[0]);
403  const auto size_type = tree_helper::CGetType(TreeM->CGetTreeReindex(size_var));
404  value_bitsize = tree_helper::Size(size_type);
405  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "store with value_bitsize=" + STR(value_bitsize));
406  }
407  else
408  {
409  const auto size_var = HLSMgr->get_produced_value(fun_id, *v);
410  const auto size_type = tree_helper::CGetType(TreeM->CGetTreeReindex(size_var));
411  value_bitsize = tree_helper::Size(size_type);
412  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "load with value_bitsize=" + STR(value_bitsize));
413  }
414  if(!(function_behavior->is_variable_mem(var->index) && HLSMgr->Rmem->is_private_memory(var->index)))
415  {
416  maximum_bus_size = std::max(maximum_bus_size, value_bitsize);
417  }
419  " with maximum_bus_size=" + STR(maximum_bus_size) + " " + curr_tn->ToString());
420  }
421  else
422  {
423  if(current_op == MEMCPY || current_op == MEMCMP || current_op == MEMSET)
424  {
425  use_databus_width = true;
426  maximum_bus_size = std::max(maximum_bus_size, 8ull);
427  if(assume_aligned_access_p)
428  {
429  THROW_ERROR("Option --aligned-access cannot be used in presence of memcpy, memcmp or memset");
430  }
431  }
432 
433  auto vr_it_end = var_read.end();
434  for(auto vr_it = var_read.begin(); vr_it != vr_it_end; ++vr_it)
435  {
436  const auto var = std::get<0>(*vr_it);
437  if(var && tree_helper::is_a_pointer(TreeM, var))
438  {
439  const auto var_node = TreeM->CGetTreeReindex(var);
440  const auto type_node = tree_helper::CGetType(var_node);
441  tree_nodeRef type_node_ptd;
442  if(GET_CONST_NODE(type_node)->get_kind() == pointer_type_K)
443  {
444  type_node_ptd = GetPointerS<const pointer_type>(GET_CONST_NODE(type_node))->ptd;
445  }
446  else if(GET_CONST_NODE(type_node)->get_kind() == reference_type_K)
447  {
448  type_node_ptd = GetPointerS<const reference_type>(GET_CONST_NODE(type_node))->refd;
449  }
450  else
451  {
452  THROW_ERROR("A pointer type is expected");
453  }
454  const auto bitsize = tree_helper::AccessedMaximumBitsize(type_node_ptd, 1);
455  maximum_bus_size = std::max(maximum_bus_size, bitsize);
457  " with maximum_bus_size=" + STR(maximum_bus_size) + " " +
458  g->CGetOpNodeInfo(*v)->node->ToString());
459  }
460  }
461  }
463  }
464  const auto top_functions = HLSMgr->CGetCallGraphManager()->GetRootFunctions();
465  const auto local_needMemoryMappedRegisters = top_functions.count(fun_id) ?
466  parameters->getOption<bool>(OPT_memory_mapped_top) :
467  HLSMgr->hasToBeInterfaced(fun_id);
468  needMemoryMappedRegisters = needMemoryMappedRegisters || local_needMemoryMappedRegisters;
469  if(local_needMemoryMappedRegisters)
470  {
471  unsigned long long addr_bus_bitsize;
472  if(parameters->isOption(OPT_addr_bus_bitsize))
473  {
474  addr_bus_bitsize = parameters->getOption<unsigned int>(OPT_addr_bus_bitsize);
475  }
476  else
477  {
478  addr_bus_bitsize = m64P ? 64 : 32;
479  }
480  for(const auto& par : behavioral_helper->GetParameters())
481  {
482  const auto type = tree_helper::CGetType(par);
483  const auto is_a_struct_union =
485  if(is_a_struct_union)
486  {
487  maximum_bus_size = std::max(addr_bus_bitsize, maximum_bus_size);
488  }
489  else
490  {
491  maximum_bus_size = std::max(tree_helper::Size(par), maximum_bus_size);
492  }
493  }
494  const auto function_return = tree_helper::GetFunctionReturnType(fnode);
495  if(function_return)
496  {
497  maximum_bus_size = std::max(tree_helper::Size(function_return), maximum_bus_size);
498  }
499  }
501  "Analyzed function for bus size: " + behavioral_helper->get_function_name());
502  }
503 
504  const auto HLS_D = HLSMgr->get_HLS_device();
505  unsigned long long bram_bitsize = 0;
506  unsigned addr_bus_bitsize = 0;
507  const auto bram_bitsize_min = HLS_D->get_parameter<unsigned int>("BRAM_bitsize_min");
508  const auto bram_bitsize_max = HLS_D->get_parameter<unsigned int>("BRAM_bitsize_max");
509  HLSMgr->Rmem->set_maxbram_bitsize(bram_bitsize_max);
510 
511  maximum_bus_size = ceil_pow2(maximum_bus_size);
512 
513  if(has_misaligned_indirect_ref || has_unaligned_accesses)
514  {
515  if(maximum_bus_size > bram_bitsize_max)
516  {
517  THROW_ERROR("Unsupported data bus size. In case, try a device supporting this BRAM BITSIZE: " +
518  STR(maximum_bus_size) + " available maximum BRAM BITSIZE: " + STR(bram_bitsize_max));
519  }
520  else
521  {
522  bram_bitsize = maximum_bus_size;
523  }
524  }
525  else if(maximum_bus_size / 2 > bram_bitsize_max)
526  {
527  THROW_ERROR("Unsupported data bus size. In case, try a device supporting this BRAM BITSIZE: " +
528  STR(maximum_bus_size / 2) + " available maximum BRAM BITSIZE: " + STR(bram_bitsize_max));
529  }
530  else
531  {
532  bram_bitsize = maximum_bus_size / 2;
533  }
534 
535  if(bram_bitsize < bram_bitsize_min)
536  {
537  bram_bitsize = bram_bitsize_min;
538  }
539 
540  if(bram_bitsize < 8)
541  {
542  bram_bitsize = 8;
543  }
544 
545  if(parameters->isOption(OPT_addr_bus_bitsize))
546  {
547  addr_bus_bitsize = parameters->getOption<unsigned int>(OPT_addr_bus_bitsize);
548  }
549  else if(use_unknown_address)
550  {
551  addr_bus_bitsize = m64P ? 64 : 32;
552  }
553  else if(has_intern_shared_data && parameters->getOption<MemoryAllocation_Policy>(OPT_memory_allocation_policy) !=
555  {
556  addr_bus_bitsize = m64P ? 64 : 32;
557  }
558  else if(HLSMgr->Rmem->get_memory_address() - HLSMgr->base_address > 0)
559  {
560  addr_bus_bitsize = m64P ? 64 : 32;
561  }
562  else
563  {
564  unsigned long long int addr_range = HLSMgr->Rmem->get_max_address();
565  if(addr_range)
566  {
567  addr_range =
568  std::max(addr_range, ((2 * HLS_D->get_parameter<unsigned long long int>("BRAM_bitsize_max")) / 8));
569  --addr_range;
570  }
571  unsigned int index;
572  for(index = 1; addr_range >= (1ull << index); ++index)
573  {
574  ;
575  }
576  addr_bus_bitsize = index;
577  if(HLSMgr->Rmem->count_non_private_internal_symbols() == 1)
578  {
579  ++addr_bus_bitsize;
580  }
581  }
582 
583  if(needMemoryMappedRegisters)
584  {
585  HLS_manager::check_bitwidth(maximum_bus_size);
586  maximum_bus_size = std::max(maximum_bus_size, static_cast<unsigned long long>(addr_bus_bitsize));
587  }
588  HLSMgr->set_address_bitsize(addr_bus_bitsize);
589  HLSMgr->Rmem->set_bus_data_bitsize(maximum_bus_size);
590  HLSMgr->Rmem->set_bus_size_bitsize(std::max(4ULL, ceil_log2(maximum_bus_size + 1ULL)));
591 
592  HLSMgr->Rmem->set_bram_bitsize(bram_bitsize);
593  HLSMgr->Rmem->set_intern_shared_data(has_intern_shared_data);
594  HLSMgr->Rmem->set_use_unknown_addresses(use_unknown_address);
595  HLSMgr->Rmem->set_unaligned_accesses(has_unaligned_accesses);
596 
598  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "---BRAM bitsize: " + STR(HLSMgr->Rmem->get_bram_bitsize()));
600  "---" + (use_databus_width ? std::string("Spec may exploit DATA bus width") :
601  std::string("Spec may not exploit DATA bus width")));
603  "---" + (!use_unknown_address ?
604  std::string("All the data have a known address") :
605  std::string("Spec accesses data having an address unknown at compile time")));
607  "---" + (!has_intern_shared_data ? std::string("Internal data is not externally accessible") :
608  std::string("Internal data may be accessed")));
610  "---DATA bus bitsize: " + STR(HLSMgr->Rmem->get_bus_data_bitsize()));
611  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "---ADDRESS bus bitsize: " + STR(HLSMgr->get_address_bitsize()));
613  "---SIZE bus bitsize: " + STR(HLSMgr->Rmem->get_bus_size_bitsize()));
614  if(HLSMgr->Rmem->has_all_pointers_resolved())
615  {
616  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "---ALL pointers have been resolved");
617  }
618  if(has_unaligned_accesses)
619  {
620  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "---Code has LOADs or STOREs with unaligned accesses");
621  }
622  if(HLSMgr->Rmem->get_allocated_parameters_memory())
623  {
625  "---Total amount of memory allocated for memory mapped parameters: " +
626  STR(HLSMgr->Rmem->get_allocated_parameters_memory()));
627  }
629  "---Internally allocated memory (no private memories): " +
630  STR(HLSMgr->Rmem->get_allocated_internal_memory()));
632  "---Internally allocated memory: " + STR(HLSMgr->Rmem->get_allocated_space()));
634 }
635 
636 void memory_allocation::allocate_parameters(unsigned int functionId, memoryRef Rmem)
637 {
638  const auto out_lvl = Rmem == HLSMgr->Rmem ? output_level : OUTPUT_LEVEL_NONE;
639  if(!Rmem)
640  {
641  Rmem = HLSMgr->Rmem;
642  }
643  const auto function_behavior = HLSMgr->CGetFunctionBehavior(functionId);
644  const auto behavioral_helper = function_behavior->CGetBehavioralHelper();
645  const auto function_return = behavioral_helper->GetFunctionReturnType(functionId);
646 
647  // Allocate memory for the start register.
648  const auto functionName = tree_helper::name_function(HLSMgr->get_tree_manager(), functionId);
649  Rmem->add_parameter(functionId, functionId, functionName,
650  behavioral_helper->get_parameters().empty() && !function_return);
651  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, out_lvl, "---Function: " + functionName);
652  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, out_lvl, "---Id: " + STR(functionId));
654  "---Base Address: " + STR(Rmem->get_parameter_base_address(functionId, functionId)));
656  "---Size: " + STR(compute_n_bytes(tree_helper::Size(
657  tree_helper::CGetType(HLSMgr->get_tree_manager()->CGetTreeReindex(functionId))))));
658  // Allocate every parameter on chip.
659  const auto& topParams = behavioral_helper->get_parameters();
660  for(auto itr = topParams.begin(), end = topParams.end(); itr != end; ++itr)
661  {
662  auto itr_next = itr;
663  ++itr_next;
664  auto par_name = behavioral_helper->PrintVariable(*itr);
665  Rmem->add_parameter(behavioral_helper->get_function_index(), *itr, par_name, !function_return && itr_next == end);
666  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, out_lvl, "-->Parameter " + par_name + " of Function " + functionName);
667  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, out_lvl, "---Id: " + STR(*itr));
669  "---Base Address: " + STR(Rmem->get_parameter_base_address(functionId, *itr)));
671  "---Size: " + STR(tree_helper::Size(HLSMgr->get_tree_manager()->CGetTreeReindex(*itr)) / 8u));
672  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, out_lvl, "<--");
673  }
674 
675  // Allocate the return value on chip.
676  if(function_return)
677  {
678  Rmem->add_parameter(behavioral_helper->get_function_index(), function_return, "@return_" + functionName, true);
679  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, out_lvl, "-->Return parameter for Function: " + functionName);
680  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, out_lvl, "---Id: " + STR(function_return));
682  "---Base Address: " + STR(Rmem->get_parameter_base_address(functionId, function_return)));
684  "---Size: " +
685  STR(tree_helper::Size(HLSMgr->get_tree_manager()->CGetTreeReindex(function_return)) / 8u));
686  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, out_lvl, "<--");
687  }
688 }
689 
691 {
692  if(memory_version == 0 or memory_version != HLSMgr->GetMemVersion())
693  {
694  return true;
695  }
696  std::map<unsigned int, unsigned int> cur_bb_ver;
697  std::map<unsigned int, unsigned int> cur_bitvalue_ver;
698  const auto CGMan = HLSMgr->CGetCallGraphManager();
699  for(const auto i : CGMan->GetReachedBodyFunctions())
700  {
701  const auto FB = HLSMgr->CGetFunctionBehavior(i);
702  cur_bb_ver[i] = FB->GetBBVersion();
703  cur_bitvalue_ver[i] = FB->GetBitValueVersion();
704  }
705  return cur_bb_ver != last_bb_ver || cur_bitvalue_ver != last_bitvalue_ver;
706 }
707 
709 {
710  const auto status = InternalExec();
711  const auto CGMan = HLSMgr->CGetCallGraphManager();
712  for(const auto i : CGMan->GetReachedBodyFunctions())
713  {
714  const auto FB = HLSMgr->CGetFunctionBehavior(i);
715  last_bb_ver[i] = FB->GetBBVersion();
716  last_bitvalue_ver[i] = FB->GetBitValueVersion();
717  }
718  memory_version = HLSMgr->GetMemVersion();
719  return status;
720 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
#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
Definition: hls_step.hpp:205
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;.
static std::string name_function(const tree_managerConstRef &tm, const unsigned int index)
Return the name of the function.
#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.
Definition: op_graph.hpp:310
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 ...
File containing functions and utilities to support the printing of debug messagges.
#define PRINT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
#define OUTPUT_LEVEL_NONE
no output print is performed.
unsigned long long int get_parameter_base_address(unsigned int funId, unsigned int var) const
Get the current base address of the given variable.
Definition: memory.cpp:410
#define GET_CLASS(obj)
Macro returning the actual type of an object.
std::map< unsigned int, unsigned int > last_bb_ver
The version of BB IR representation on which this step was applied.
~memory_allocation() override
Destructor.
Definition of the class representing a generic C application.
const int output_level
The output level.
only external memory access Datapath see only 1 memory port, while the bus manage parallel accesses ...
static bool is_a_misaligned_vector(const tree_managerConstRef &TM, const unsigned int index)
Return true if the treenode index is a a misaligned access to a vector data object.
RelationshipType
The relationship type.
Source must be executed to satisfy target.
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.
#define GET_NAME(data, vertex_index)
Helper macro returning the name associated with a node.
virtual DesignFlowStep_Status InternalExec()=0
Execute the step.
MemoryAllocation_ChannelsType
The number of channels.
static bool IsVolatile(const tree_nodeConstRef &tn)
return true in case the tree node corresponds to a volatile variable
all objects that need to be stored in memory are allocated on an external memory
MemoryAllocationSpecialization(const MemoryAllocation_Policy memory_allocation_policy, const MemoryAllocation_ChannelsType memory_allocation_channels_type)
Constructor.
#define OUTPUT_LEVEL_MINIMUM
minimum debugging print is performed.
redefinition of map to manage ordered/unordered structures
static bool is_packed_access(const tree_managerConstRef &TreeM, unsigned int node_index)
Check if the access is on a packed data structure or not.
#define TYPE_LOAD
Constant string identifying a memory load operation.
Definition: op_graph.hpp:172
#define THROW_WARNING(str_expr)
helper function used to throw a warning in a standard way: though it uses PRINT_DBG_MEX, the debug level used is such that the message is always printed
Definition: exceptions.hpp:300
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
memory_allocation(const ParameterConstRef _parameters, const HLS_managerRef HLSMgr, const DesignFlowManagerConstRef design_flow_manager, const HLSFlowStep_Type hls_flow_step_type, const HLSFlowStepSpecializationConstRef hls_flow_step_specialization=HLSFlowStepSpecializationConstRef())
Constructor.
#define max
Definition: backprop.h:17
#define MEMSET
constant string identifying the operation performed when two objects are memsetted.
Definition: op_graph.hpp:320
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
T ceil_log2(T x)
Return the smallest n such that 2**n >= X.
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
Control flow graph.
all global variables, static variables and strings are allocated on BRAMs
HLSFlowStep_Type
Definition: hls_step.hpp:95
const unsigned int index
Represent the index read from the raw file and the index-1 of the vector of tree_node associated to t...
Definition: tree_node.hpp:146
#define index(x, y)
Definition: Keccak.c:74
redefinition of set to manage ordered/unordered structures
#define TYPE_STORE
Constant string identifying a memory store operation.
Definition: op_graph.hpp:177
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.
Definition: op_graph.hpp:315
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
Classes specification of the tree_node data structures.
const MemoryAllocation_ChannelsType memory_allocation_channels_type
number of channels
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
Call graph hierarchy.
Base class to allocate memories in high-level synthesis.
static bool is_a_pointer(const tree_managerConstRef &TM, const unsigned int index)
Return if treenode index is a pointer.
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
std::map< unsigned int, unsigned int > last_bitvalue_ver
The version of bit value IR representation on which this step was applied.
T compute_n_bytes(T bitsize)
static void check_bitwidth(unsigned long long prec)
check if the maximum bitwidth used for registers, busses, muxes, etc. is compatible with prec ...
This file collects some utility functions.
for each memory at maximum n parallel direct accesses and one indirect access
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
struct definition of the type node structures.
Definition: tree_node.hpp:1318
Class specification of the tree_reindex support class.
const CustomUnorderedSet< std::tuple< HLSFlowStep_Type, HLSFlowStepSpecializationConstRef, HLSFlowStep_Relationship > > ComputeHLSRelationships(const DesignFlowStep::RelationshipType relationship_type) const override
Compute the relationship of this step.
T * GetPointer(const refcount< U > &t)
Template function used to hide dynamic_cast The template parameter T represents a type of an object h...
Definition: refcount.hpp:237
std::string GetKindText() const override
Return the string representation of this.
DesignFlowStep_Status Exec() override
Execute the step.
unsigned int memory_version
The version of memory representation on which this step was applied.
all local variables, static variables and strings are allocated on BRAMs
for each memory at maximum n parallel direct accesses and n parallel indirect accesses ...
Data structures used in operations graph.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
static tree_nodeConstRef CGetType(const tree_nodeConstRef &node)
Return the treenode of the type of node.
static bool IsStructType(const tree_nodeConstRef &type)
Return true if treenode is a record.
for each memory at maximum one direct access and one indirect access
Classes specification of the tree_node data structures not present in the gcc.
this class is used to manage the command-line or XML options.
std::string GetSignature() const override
Return the contribution to the signature of a step given by the specialization.
Wrapper to call graph.
Generic device description.
int debug_level
The debug level.
The information about how memory allocation has to be specialized.
#define OUTPUT_LEVEL_VERBOSE
verbose debugging print is performed.
refcount< const HLSFlowStepSpecialization > HLSFlowStepSpecializationConstRef
const refcount definition of the class
Definition: hls_step.hpp:93
all objects that need to be stored in memory are allocated on BRAMs
#define DEBUG_LEVEL_VERBOSE
verbose debugging print is performed.
const MemoryAllocation_Policy memory_allocation_policy
memory allocation policy
static tree_nodeConstRef GetFunctionReturnType(const tree_nodeConstRef &function, bool void_as_null=true)
Return the return type of a function.
Datastructure to represent memory information in high-level synthesis.
MemoryAllocation_Policy
The allocation memory polycy.
void add_parameter(unsigned int funID_scope, unsigned int var, const std::string &var_name, bool is_last)
Allocates a parameter to the set of the interface registers.
Definition: memory.cpp:323
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.
#define THROW_ASSERT(cond, str_expr)
helper function used to check an assert and if needed to throw an error in a standard way ...
Definition: exceptions.hpp:289

Generated on Mon Feb 12 2024 13:02:54 for PandA-2024.02 by doxygen 1.8.13