PandA-2024.02
memory.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  */
46 #include "memory.hpp"
47 #include "memory_cs.hpp"
48 
49 #include "memory_symbol.hpp"
50 
51 #include "application_manager.hpp"
52 #include "call_graph_manager.hpp"
53 
54 #include "Parameter.hpp"
55 #include "funit_obj.hpp"
56 #include "tree_helper.hpp"
57 #include "tree_manager.hpp"
58 
59 #include "structural_manager.hpp"
60 #include "structural_objects.hpp"
61 
62 #include "exceptions.hpp"
63 #include "utility.hpp"
64 
65 #include "polixml.hpp"
66 #include "xml_helper.hpp"
67 
68 #include "math_function.hpp"
69 
71 #include <algorithm>
72 #include <vector>
73 
75 #include "tree_node.hpp"
76 #include "tree_reindex.hpp"
77 
81 static inline unsigned long long int align(unsigned long long int address, unsigned long long int alignment)
82 {
83  return ((address / alignment) + (address % alignment != 0)) * alignment;
84 }
85 
88 
89 memory::memory(const tree_managerConstRef _TreeM, unsigned long long int _off_base_address, unsigned int max_bram,
90  bool _null_pointer_check, bool initial_internal_address_p,
91  unsigned long long int initial_internal_address, const unsigned int& _bus_addr_bitsize)
92  : TreeM(_TreeM),
93  maximum_private_memory_size(0),
94  total_amount_of_private_memory(0),
95  total_amount_of_parameter_memory(0),
96  off_base_address(_off_base_address),
97  next_off_base_address(_off_base_address),
98  bus_data_bitsize(0),
99  bus_size_bitsize(0),
100  bram_bitsize(0),
101  maxbram_bitsize(0),
102  intern_shared_data(false),
103  use_unknown_addresses(false),
104  unaligned_accesses(false),
105  all_pointers_resolved(false),
106  implicit_memcpy(false),
107  parameter_alignment(16),
108  null_pointer_check(_null_pointer_check),
109  packed_vars(false),
110  bus_addr_bitsize(_bus_addr_bitsize),
111  enable_hls_bit_value(false)
112 {
113  const auto max_bus_size = 2U * max_bram;
115  if(null_pointer_check && !initial_internal_address_p)
116  {
117  next_base_address = internal_base_address_start = max_bus_size / 8;
118  }
119  else if(initial_internal_address_p && initial_internal_address != 0)
120  {
121  initial_internal_address = align(initial_internal_address, internal_base_address_alignment);
122  next_base_address = internal_base_address_start = initial_internal_address;
123  }
124  else
125  {
127  }
128 }
129 
130 memory::~memory() = default;
131 
133  unsigned long long _off_base_address, unsigned int max_bram, bool _null_pointer_check,
134  bool initial_internal_address_p, unsigned int initial_internal_address,
135  const unsigned int& _address_bitsize)
136 {
137  if(_parameters->getOption<bool>(OPT_parse_pragma) && _parameters->isOption(OPT_context_switch))
138  {
139  return memoryRef(new memory_cs(_TreeM, _off_base_address, max_bram, _null_pointer_check,
140  initial_internal_address_p, initial_internal_address, _address_bitsize));
141  }
142  else
143  {
144  return memoryRef(new memory(_TreeM, _off_base_address, max_bram, _null_pointer_check, initial_internal_address_p,
145  initial_internal_address, _address_bitsize));
146  }
147 }
148 
149 std::map<unsigned int, memory_symbolRef> memory::get_ext_memory_variables() const
150 {
151  return external;
152 }
153 
154 unsigned long long int memory::compute_next_base_address(unsigned long long int address, unsigned int var,
155  unsigned long long int alignment) const
156 {
157  const auto node = TreeM->CGetTreeReindex(var);
158  unsigned long long size = 0;
159 
160  // The __builtin_wait_call associate an address to the call site to
161  // identify it. For this case we are allocating a word.
162  if(GetPointer<const gimple_call>(GET_CONST_NODE(node)))
163  {
165  }
166  else
167  {
170  }
172  return align(address + size, alignment);
173 }
174 
175 void memory::add_internal_variable(unsigned int funID_scope, unsigned int var, const std::string& var_name)
176 {
177  memory_symbolRef m_sym;
178  if(in_vars.find(var) != in_vars.end())
179  {
180  m_sym = in_vars[var];
181  }
182  else if(is_private_memory(var))
183  {
185  {
187  m_sym = memory_symbolRef(new memory_symbol(var, var_name, internal_base_address_start, funID_scope));
188  }
189  else
190  {
191  m_sym = memory_symbolRef(new memory_symbol(var, var_name, 0, funID_scope));
192  }
193  }
194  else
195  {
197  m_sym = memory_symbolRef(new memory_symbol(var, var_name, next_base_address, funID_scope));
198  }
199  add_internal_symbol(funID_scope, var, m_sym);
200 }
201 
202 void memory::add_internal_variable_proxy(unsigned int funID_scope, unsigned int var)
203 {
204  internal_variable_proxy[funID_scope].insert(var);
205  proxied_variables.insert(var);
206 }
207 
209 {
210  THROW_ASSERT(has_proxied_internal_variables(funID_scope), "No proxy variables for " + STR(funID_scope));
211  return internal_variable_proxy.find(funID_scope)->second;
212 }
213 
214 bool memory::has_proxied_internal_variables(unsigned int funID_scope) const
215 {
216  return internal_variable_proxy.find(funID_scope) != internal_variable_proxy.end();
217 }
218 
219 bool memory::is_a_proxied_variable(unsigned int var) const
220 {
221  return proxied_variables.find(var) != proxied_variables.end();
222 }
223 
225 {
226  read_only_vars.insert(var);
227 }
228 
229 bool memory::is_read_only_variable(unsigned var) const
230 {
231  return read_only_vars.find(var) != read_only_vars.end();
232 }
233 
234 void memory::add_internal_symbol(unsigned int funID_scope, unsigned int var, const memory_symbolRef m_sym)
235 {
236  if(external.find(var) != external.end())
237  {
238  THROW_WARNING("The variable " + STR(var) + " has been already allocated out of the module");
239  }
240  if(parameter.find(var) != parameter.end())
241  {
242  THROW_WARNING("The variable " + STR(var) + " has been already set as a parameter");
243  }
244  THROW_ASSERT(in_vars.find(var) == in_vars.end() || is_private_memory(var),
245  "variable already allocated inside this module");
246 
247  internal[funID_scope][var] = m_sym;
248  if(GetPointer<const gimple_call>(TreeM->CGetTreeNode(var)))
249  {
250  callSites[var] = m_sym;
251  }
252  else
253  {
254  in_vars[var] = m_sym;
255  }
256 
257  if(is_private_memory(var))
258  {
259  const unsigned long long allocated_memory = compute_n_bytes(tree_helper::Size(TreeM->CGetTreeReindex(var)));
260  rangesize[var] = align(allocated_memory, internal_base_address_alignment);
261  total_amount_of_private_memory += allocated_memory;
263  }
264  else
265  {
266  const auto address = m_sym->get_address();
267  const auto new_address = compute_next_base_address(address, var, internal_base_address_alignment);
269  rangesize[var] = next_base_address - address;
270  }
271 }
272 
274 {
275  unsigned int n_non_private = 0;
276  for(const auto& iv_pair : in_vars)
277  {
278  if(!is_private_memory(iv_pair.first))
279  {
280  ++n_non_private;
281  }
282  }
283  return n_non_private;
284 }
285 
286 void memory::add_external_variable(unsigned int var, const std::string& var_name)
287 {
290  add_external_symbol(var, m_sym);
291 }
292 
293 void memory::add_external_symbol(unsigned int var, const memory_symbolRef m_sym)
294 {
295  if(in_vars.find(var) != in_vars.end())
296  {
297  THROW_WARNING("The variable " + STR(var) + " has been already internally allocated");
298  }
299  if(parameter.find(var) != parameter.end())
300  {
301  THROW_WARNING("The variable " + STR(var) + " has been already set as a parameter");
302  }
303  external[var] = m_sym;
304  const auto new_address = compute_next_base_address(m_sym->get_address(), var, external_base_address_alignment);
305  next_off_base_address = std::max(next_off_base_address, new_address);
306 }
307 
308 void memory::add_private_memory(unsigned int var)
309 {
310  private_memories.insert(var);
311 }
312 
313 void memory::set_sds_var(unsigned int var, bool value)
314 {
316 }
317 
318 void memory::add_source_value(unsigned int var, unsigned int value)
319 {
320  source_values[var].insert(value);
321 }
322 
323 void memory::add_parameter(unsigned int funID_scope, unsigned int var, const std::string& var_name, bool is_last)
324 {
325  memory_symbolRef m_sym = memory_symbolRef(new memory_symbol(var, var_name, next_base_address, funID_scope));
326  add_parameter_symbol(funID_scope, var, m_sym);
327  if(is_last)
328  {
329  const auto address = next_base_address;
333  }
334 }
335 
336 void memory::add_parameter_symbol(unsigned int funID_scope, unsigned int var, const memory_symbolRef m_sym)
337 {
338  if(external.find(var) != external.end())
339  {
340  THROW_WARNING("The variable " + STR(var) + " has been already allocated out of the module");
341  }
342  if(in_vars.find(var) != in_vars.end())
343  {
344  THROW_WARNING("The variable " + STR(var) + " has been already internally allocated");
345  }
347  params[var] = parameter[funID_scope][var] = m_sym;
348  const auto address = m_sym->get_address();
352 }
353 
354 unsigned long long int memory::get_memory_address() const
355 {
356  return next_off_base_address;
357 }
358 
359 bool memory::is_internal_variable(unsigned int funID_scope, unsigned int var) const
360 {
361  return internal.find(funID_scope) != internal.end() &&
362  internal.find(funID_scope)->second.find(var) != internal.find(funID_scope)->second.end();
363 }
364 
365 bool memory::is_external_variable(unsigned int var) const
366 {
367  return external.find(var) != external.end();
368 }
369 
370 bool memory::is_private_memory(unsigned int var) const
371 {
372  return private_memories.find(var) != private_memories.end();
373 }
374 
375 bool memory::is_sds_var(unsigned int var) const
376 {
377  THROW_ASSERT(has_sds_var(var), "variable not classified " + STR(var));
378  return same_data_size_accesses.find(var)->second;
379 }
380 
381 bool memory::has_sds_var(unsigned int var) const
382 {
383  return same_data_size_accesses.find(var) != same_data_size_accesses.end();
384 }
385 
386 bool memory::is_parameter(unsigned int funID_scope, unsigned int var) const
387 {
388  return parameter.find(funID_scope) != parameter.end() &&
389  parameter.find(funID_scope)->second.find(var) != parameter.find(funID_scope)->second.end();
390 }
391 
392 unsigned long long int memory::get_callSite_base_address(unsigned int var) const
393 {
394  THROW_ASSERT(callSites.find(var) != callSites.end(), "Variable not yet allocated");
395  return callSites.at(var)->get_address();
396 }
397 
398 unsigned long long int memory::get_internal_base_address(unsigned int var) const
399 {
400  THROW_ASSERT(in_vars.find(var) != in_vars.end(), "Variable not yet allocated");
401  return in_vars.at(var)->get_address();
402 }
403 
404 unsigned long long int memory::get_external_base_address(unsigned int var) const
405 {
406  THROW_ASSERT(external.find(var) != external.end(), "Variable not yet allocated");
407  return external.at(var)->get_address();
408 }
409 
410 unsigned long long int memory::get_parameter_base_address(unsigned int funId, unsigned int var) const
411 {
412  THROW_ASSERT(parameter.find(funId) != parameter.end(), "Function not yet allocated");
413  THROW_ASSERT(parameter.at(funId).find(var) != parameter.at(funId).end(), "Function not yet allocated");
414  return parameter.at(funId).at(var)->get_address();
415 }
416 
417 std::map<unsigned int, memory_symbolRef> memory::get_function_vars(unsigned int funID_scope) const
418 {
419  const auto internal_it = internal.find(funID_scope);
420  if(internal_it == internal.end())
421  {
422  return std::map<unsigned int, memory_symbolRef>();
423  }
424  return internal_it->second;
425 }
426 
427 std::map<unsigned int, memory_symbolRef> memory::get_function_parameters(unsigned int funID_scope) const
428 {
429  if(parameter.find(funID_scope) == parameter.end())
430  {
431  return std::map<unsigned int, memory_symbolRef>();
432  }
433  return parameter.at(funID_scope);
434 }
435 
436 bool memory::has_callSite_base_address(unsigned int var) const
437 {
438  return callSites.find(var) != callSites.end();
439 }
440 
441 bool memory::has_internal_base_address(unsigned int var) const
442 {
443  return in_vars.find(var) != in_vars.end();
444 }
445 
446 bool memory::has_external_base_address(unsigned int var) const
447 {
448  return external.find(var) != external.end();
449 }
450 
451 bool memory::has_parameter_base_address(unsigned int var, unsigned int funId) const
452 {
453  auto itr = parameter.find(funId);
454  if(itr == parameter.end())
455  {
456  return false;
457  }
458  return itr->second.find(var) != itr->second.end();
459 }
460 
461 bool memory::has_base_address(unsigned int var) const
462 {
463  return external.find(var) != external.end() || in_vars.find(var) != in_vars.end() ||
464  params.find(var) != params.end() || callSites.find(var) != callSites.end();
465 }
466 
467 unsigned long long memory::get_base_address(unsigned int var, unsigned int funId) const
468 {
469  THROW_ASSERT(has_base_address(var), "Variable not yet allocated: @" + STR(var));
471  {
472  return get_callSite_base_address(var);
473  }
475  {
476  return get_internal_base_address(var);
477  }
478  if(funId && has_parameter_base_address(var, funId))
479  {
480  return get_parameter_base_address(var, funId);
481  }
482  return get_external_base_address(var);
483 }
484 
485 unsigned long long int memory::get_first_address(unsigned int funId) const
486 {
487  unsigned long long int minAddress = UINT_MAX;
488  const auto internal_it = internal.find(funId);
489  if(internal_it != internal.end())
490  {
491  for(const auto& internalVar : internal_it->second)
492  {
493  const auto& var = internalVar.first;
494  if(internalVar.second && !is_private_memory(var) && !has_parameter_base_address(var, funId))
495  {
496  minAddress = std::min(minAddress, internalVar.second->get_address());
497  }
498  }
499  }
500  if(minAddress == UINT_MAX)
501  {
502  const auto& paramsVar = parameter.at(funId);
503  for(const auto& itr : paramsVar)
504  {
505  const auto& var = itr.first;
506  if(!is_private_memory(var))
507  {
508  minAddress = std::min(minAddress, itr.second->get_address());
509  }
510  }
511  }
512  return minAddress;
513 }
514 
515 unsigned long long int memory::get_last_address(unsigned int funId, const application_managerRef AppMgr) const
516 {
517  unsigned long long int maxAddress = 0;
518  const auto internal_it = internal.find(funId);
519  if(internal_it != internal.end())
520  {
521  for(const auto& internalVar : internal_it->second)
522  {
523  const auto& var = internalVar.first;
524  if(!is_private_memory(var) && !has_parameter_base_address(var, funId) && has_base_address(var))
525  {
526  maxAddress = std::max(maxAddress, internalVar.second->get_address() +
528  }
529  }
530  }
531  if(AppMgr->hasToBeInterfaced(funId))
532  {
533  const auto& paramsVar = get_function_parameters(funId);
534  for(const auto& itr : paramsVar)
535  {
536  const auto& var = itr.first;
537  maxAddress =
538  std::max(maxAddress, itr.second->get_address() + tree_helper::Size(TreeM->CGetTreeReindex(var)) / 8);
539  }
540  }
541  const auto calledSet = AppMgr->CGetCallGraphManager()->get_called_by(funId);
542  for(const auto Itr : calledSet)
543  {
544  if(!AppMgr->hasToBeInterfaced(Itr))
545  {
546  maxAddress = std::max(get_last_address(Itr, AppMgr), maxAddress);
547  }
548  }
549 
550  return maxAddress;
551 }
552 
553 memory_symbolRef memory::get_symbol(unsigned int var, unsigned int funId) const
554 {
555  THROW_ASSERT(has_base_address(var), "Variable not yet allocated: @" + STR(var));
557  {
558  return callSites.at(var);
559  }
561  {
562  return in_vars.at(var);
563  }
564  if(funId && has_parameter_base_address(var, funId))
565  {
566  return parameter.at(funId).at(var);
567  }
568  return external.at(var);
569 }
570 
571 unsigned long long int memory::get_rangesize(unsigned int var) const
572 {
573  THROW_ASSERT(has_base_address(var), "Variable not yet allocated: @" + STR(var));
574  return rangesize.at(var);
575 }
576 
577 void memory::reserve_space(unsigned long long space)
578 {
579  next_off_base_address += space;
581 }
582 
583 void memory::reserve_internal_space(unsigned long long int space)
584 {
585  next_base_address += space;
587 }
588 
589 unsigned long long int memory::get_allocated_space() const
590 {
592 }
593 
594 unsigned long long int memory::get_allocated_parameters_memory() const
595 {
597 }
598 
599 unsigned long long int memory::get_allocated_internal_memory() const
600 {
602 }
603 
604 unsigned long long int memory::get_next_internal_base_address() const
605 {
606  return next_base_address;
607 }
608 
609 unsigned long long memory::get_max_address() const
610 {
612 }
613 
614 bool memory::is_parm_decl_copied(unsigned int var) const
615 {
616  return parm_decl_copied.find(var) != parm_decl_copied.end();
617 }
618 
619 void memory::add_parm_decl_copied(unsigned int var)
620 {
621  parm_decl_copied.insert(var);
622 }
623 
624 bool memory::is_parm_decl_stored(unsigned int var) const
625 {
626  return parm_decl_stored.find(var) != parm_decl_stored.end();
627 }
628 
629 void memory::add_parm_decl_stored(unsigned int var)
630 {
631  parm_decl_stored.insert(var);
632 }
633 
634 bool memory::is_actual_parm_loaded(unsigned int var) const
635 {
636  return actual_parm_loaded.find(var) != actual_parm_loaded.end();
637 }
638 
639 void memory::add_actual_parm_loaded(unsigned int var)
640 {
641  actual_parm_loaded.insert(var);
642 }
643 
644 void memory::set_internal_base_address_alignment(unsigned long long _internal_base_address_alignment)
645 {
646  THROW_ASSERT(_internal_base_address_alignment &&
647  !(_internal_base_address_alignment & (_internal_base_address_alignment - 1)),
648  "alignment must be a power of two");
649  internal_base_address_alignment = _internal_base_address_alignment;
652 }
653 
655 {
656  std::map<std::string, std::string> res_parameters;
657 
659  {
660  const auto current_src_parameters =
661  string_to_container<std::vector<std::string>>(src->GetParameter(MEMORY_PARAMETER), ";");
662  for(const auto& current_src_parameter : current_src_parameters)
663  {
664  std::vector<std::string> current_parameter =
665  string_to_container<std::vector<std::string>>(current_src_parameter, "=");
666  res_parameters[current_parameter[0]] = current_parameter[1];
667  }
668  }
669 
670  const auto srcModule = GetPointer<const module>(src);
671  // std::cout << srcModule->get_id() << std::endl;
672  if(srcModule)
673  {
674  for(unsigned int i = 0; i < srcModule->get_internal_objects_size(); ++i)
675  {
676  const auto subModule = srcModule->get_internal_object(i);
677  if(subModule->ExistsParameter(MEMORY_PARAMETER))
678  {
679  const auto current_src_parameters =
680  string_to_container<std::vector<std::string>>(subModule->GetParameter(MEMORY_PARAMETER), ";");
681  for(const auto& current_src_parameter : current_src_parameters)
682  {
683  const auto current_parameter = string_to_container<std::vector<std::string>>(current_src_parameter, "=");
684  res_parameters[current_parameter[0]] = current_parameter[1];
685  }
686  }
687  }
688  }
689 
691  {
693  }
694  const auto current_tgt_parameters =
695  string_to_container<std::vector<std::string>>(tgt->get_circ()->GetParameter(MEMORY_PARAMETER), ";");
696  for(const auto& current_tgt_parameter : current_tgt_parameters)
697  {
698  const auto current_parameter = string_to_container<std::vector<std::string>>(current_tgt_parameter, "=");
699  if(res_parameters.find(current_parameter[0]) != res_parameters.end() &&
700  res_parameters[current_parameter[0]] != current_parameter[1])
701  {
702  THROW_ERROR("The parameter \"" + current_parameter[0] +
703  "\" has been set with (at least) two different values");
704  }
705  res_parameters[current_parameter[0]] = current_parameter[1];
706  }
707 
708  if(res_parameters.size() == 0)
709  {
710  return;
711  }
712 
713  std::string memory_parameters;
714  for(const auto& res_parameter : res_parameters)
715  {
716  if(memory_parameters.size())
717  {
718  memory_parameters += ";";
719  }
720  memory_parameters += res_parameter.first + "=" + res_parameter.second;
721  }
722  tgt->get_circ()->SetParameter(MEMORY_PARAMETER, memory_parameters);
723 }
724 
725 void memory::add_memory_parameter(const structural_managerRef SM, const std::string& name, const std::string& value)
726 {
728  {
730  }
731  auto memory_parameters = SM->get_circ()->GetParameter(MEMORY_PARAMETER) + ";";
732  const auto current_parameters = string_to_container<std::vector<std::string>>(memory_parameters, ";");
733  for(const auto& l : current_parameters)
734  {
735  const auto current_parameter = string_to_container<std::vector<std::string>>(l, "=");
736  THROW_ASSERT(current_parameter.size() == 2, "expected two elements");
737  if(current_parameter[0] == name)
738  {
739  if(value == current_parameter[1])
740  {
741  return;
742  }
743  THROW_ERROR("The parameter \"" + name + "\" has been set with (at least) two different values: " + value +
744  " != " + current_parameter[1]);
745  }
746  }
747  memory_parameters += name + "=" + value;
748  SM->get_circ()->SetParameter(MEMORY_PARAMETER, memory_parameters);
749 }
750 
752 {
753  const auto Enode = node->add_child_element("HLS_memory");
754  const auto base_address = off_base_address;
755  WRITE_XVM(base_address, Enode);
756  if(internal.size() || parameter.size())
757  {
758  const auto IntNode = Enode->add_child_element("internal_memory");
759  for(auto iIt = internal.begin(); iIt != internal.end(); ++iIt)
760  {
761  const auto ScopeNode = IntNode->add_child_element("scope");
762  const auto id = "@" + STR(iIt->first);
763  WRITE_XVM(id, ScopeNode);
764  const auto name = tree_helper::name_function(TreeM, iIt->first);
765  WRITE_XVM(name, ScopeNode);
766  for(auto vIt = iIt->second.begin(); vIt != iIt->second.end(); ++vIt)
767  {
768  const auto VarNode = ScopeNode->add_child_element("variable");
769  const auto variable = "@" + STR(vIt->second->get_variable());
770  WRITE_XNVM(id, variable, VarNode);
771  const auto address = vIt->second->get_address();
772  WRITE_XVM(address, VarNode);
773  const auto var_symbol_name = vIt->second->get_symbol_name();
774  WRITE_XNVM(name, var_symbol_name, VarNode);
775  const auto var_name = vIt->second->get_name();
776  WRITE_XNVM(name, var_name, VarNode);
777  }
778  if(parameter.find(iIt->first) != parameter.end())
779  {
780  const auto params0 = parameter.at(iIt->first);
781  for(auto vIt = params0.begin(); vIt != params0.end(); ++vIt)
782  {
783  const auto VarNode = ScopeNode->add_child_element("parameter");
784  const auto variable = "@" + STR(vIt->second->get_variable());
785  WRITE_XNVM(id, variable, VarNode);
786  const auto address = vIt->second->get_address();
787  WRITE_XVM(address, VarNode);
788  const auto var_symbol_name = vIt->second->get_symbol_name();
789  WRITE_XNVM(symbol, var_symbol_name, VarNode);
790  const auto var_name = vIt->second->get_symbol_name();
791  WRITE_XNVM(symbol, var_name, VarNode);
792  }
793  }
794  }
795  if(parameter.size())
796  {
797  for(auto iIt = internal.begin(); iIt != internal.end(); ++iIt)
798  {
799  if(internal.find(iIt->first) != internal.end())
800  {
801  continue;
802  }
803  const auto ScopeNode = IntNode->add_child_element("scope");
804  const auto id = "@" + STR(iIt->first);
805  WRITE_XVM(id, ScopeNode);
806  const auto name = tree_helper::name_function(TreeM, iIt->first);
807  WRITE_XVM(name, ScopeNode);
808  const auto params0 = parameter.find(iIt->first)->second;
809  for(auto vIt = params0.begin(); vIt != params0.end(); ++vIt)
810  {
811  const auto VarNode = ScopeNode->add_child_element("parameter");
812  const auto variable = "@" + STR(vIt->second->get_variable());
813  WRITE_XNVM(id, variable, VarNode);
814  unsigned long long int address = vIt->second->get_address();
815  WRITE_XVM(address, VarNode);
816  const auto var_symbol_name = vIt->second->get_symbol_name();
817  WRITE_XNVM(symbol, var_symbol_name, VarNode);
818  const auto var_name = vIt->second->get_symbol_name();
819  WRITE_XNVM(symbol, var_name, VarNode);
820  }
821  }
822  }
823  }
824  if(external.size())
825  {
826  const auto ExtNode = Enode->add_child_element("external_memory");
827  for(auto eIt = external.begin(); eIt != external.end(); ++eIt)
828  {
829  const auto VarNode = ExtNode->add_child_element("variable");
830  const auto variable = "@" + STR(eIt->second->get_variable());
831  WRITE_XNVM(id, variable, VarNode);
832  const auto address = eIt->second->get_address();
833  WRITE_XVM(address, VarNode);
834  const auto var_name = eIt->second->get_symbol_name();
835  WRITE_XNVM(symbol, var_name, VarNode);
836  }
837  }
838 }
839 
841 {
842  if(!ref)
843  {
844  return true;
845  }
846  auto neEQMapSymbolRef = [](const std::map<unsigned int, memory_symbolRef>& ref1,
847  const std::map<unsigned int, memory_symbolRef>& ref2) -> bool {
848  if(ref1.size() != ref2.size())
849  {
850  return true;
851  }
852  else
853  {
854  std::map<unsigned int, memory_symbolRef>::const_iterator i_it, j_it;
855  for(i_it = ref1.begin(), j_it = ref2.begin(); i_it != ref1.end(); ++i_it, ++j_it)
856  {
857  if(i_it->first != j_it->first)
858  {
859  return true;
860  }
861  if((i_it->second)->notEQ(*(j_it->second)))
862  {
863  return true;
864  }
865  }
866  }
867  return false;
868  };
869  auto neEQ2MapSymbolRef =
870  [&neEQMapSymbolRef](const std::map<unsigned int, std::map<unsigned int, memory_symbolRef>>& ref1,
871  const std::map<unsigned int, std::map<unsigned int, memory_symbolRef>>& ref2) -> bool {
872  if(ref1.size() != ref2.size())
873  {
874  return true;
875  }
876  else
877  {
878  std::map<unsigned int, std::map<unsigned int, memory_symbolRef>>::const_iterator i_it, j_it;
879  for(i_it = ref1.begin(), j_it = ref2.begin(); i_it != ref1.end(); ++i_it, ++j_it)
880  {
881  if(i_it->first != j_it->first)
882  {
883  return true;
884  }
885  if(neEQMapSymbolRef(i_it->second, j_it->second))
886  {
887  return true;
888  }
889  }
890  }
891  return false;
892  };
893  if(neEQMapSymbolRef(external, ref->external))
894  {
895  return true;
896  }
897  if(neEQ2MapSymbolRef(internal, ref->internal))
898  {
899  return true;
900  }
902  {
903  return true;
904  }
906  {
907  return true;
908  }
909  if(read_only_vars != ref->read_only_vars)
910  {
911  return true;
912  }
913  if(neEQMapSymbolRef(in_vars, ref->in_vars))
914  {
915  return true;
916  }
917  if(rangesize != ref->rangesize)
918  {
919  return true;
920  }
921  if(neEQ2MapSymbolRef(parameter, ref->parameter))
922  {
923  return true;
924  }
925  if(neEQMapSymbolRef(params, ref->params))
926  {
927  return true;
928  }
929  if(neEQMapSymbolRef(callSites, ref->callSites))
930  {
931  return true;
932  }
934  {
935  return true;
936  }
938  {
939  return true;
940  }
941  // may oscillate
942  // if(source_values != ref->source_values)
943  // return true;
945  {
946  return true;
947  }
949  {
950  return true;
951  }
953  {
954  return true;
955  }
957  {
958  return true;
959  }
961  {
962  return true;
963  }
965  {
966  return true;
967  }
969  {
970  return true;
971  }
973  {
974  return true;
975  }
977  {
978  return true;
979  }
981  {
982  return true;
983  }
985  {
986  return true;
987  }
989  {
990  return true;
991  }
992  if(bram_bitsize != ref->bram_bitsize)
993  {
994  return true;
995  }
996  if(maxbram_bitsize != ref->maxbram_bitsize)
997  {
998  return true;
999  }
1001  {
1002  return true;
1003  }
1005  {
1006  return true;
1007  }
1009  {
1010  return true;
1011  }
1013  {
1014  return true;
1015  }
1016  if(implicit_memcpy != ref->implicit_memcpy)
1017  {
1018  return true;
1019  }
1021  {
1022  return true;
1023  }
1025  {
1026  return true;
1027  }
1029  {
1030  return true;
1031  }
1032  // if(n_mem_operations_per_var != ref->n_mem_operations_per_var)
1033  // return true;
1035  {
1036  return true;
1037  }
1039  {
1040  return true;
1041  }
1042  if(maximum_loads != ref->maximum_loads)
1043  {
1044  return true;
1045  }
1046  if(need_bus != ref->need_bus)
1047  {
1048  return true;
1049  }
1050  if(packed_vars != ref->packed_vars)
1051  {
1052  return true;
1053  }
1055  {
1056  return true;
1057  }
1058 
1059  return false;
1060 }
1061 
1063 {
1064  const auto Enode = node->add_child_element("memory_allocation");
1065  const auto base_address = off_base_address;
1066  WRITE_XVM(base_address, Enode);
1067  for(const auto& int_obj : internal)
1068  {
1069  for(const auto& var_obj : int_obj.second)
1070  {
1071  const auto ObjNode = Enode->add_child_element("object");
1072  const auto scope = tree_helper::name_function(TreeM, int_obj.first);
1073  WRITE_XVM(scope, ObjNode);
1074  const auto name = var_obj.second->get_name();
1075  WRITE_XVM(name, ObjNode);
1076  WRITE_XNVM(is_internal, "T", ObjNode);
1077  }
1078  }
1079  for(const auto& ext_obj : external)
1080  {
1081  const auto ObjNode = Enode->add_child_element("object");
1082  const auto name = ext_obj.second->get_name();
1083  WRITE_XVM(name, ObjNode);
1084  WRITE_XNVM(is_internal, "F", ObjNode);
1085  }
1086 }
1087 
1088 void memory::xwrite(const std::string& filename)
1089 {
1090  try
1091  {
1092  xml_document document;
1093  const auto nodeRoot = document.create_root_node("memory");
1094  xwrite2(nodeRoot);
1095  document.write_to_file_formatted(filename);
1096  }
1097  catch(const char* msg)
1098  {
1099  std::cerr << msg << std::endl;
1100  }
1101  catch(const std::string& msg)
1102  {
1103  std::cerr << msg << std::endl;
1104  }
1105  catch(const std::exception& ex)
1106  {
1107  std::cout << "Exception caught: " << ex.what() << std::endl;
1108  }
1109  catch(...)
1110  {
1111  std::cerr << "unknown exception" << std::endl;
1112  }
1113 }
static void propagate_memory_parameters(const structural_objectRef src, const structural_managerRef tgt)
Propagates the memory parameters from the source (innermost) module to the target (outermost) one...
Definition: memory.cpp:654
unsigned long long int off_base_address
it represents the base address of the external memory
Definition: memory.hpp:133
std::map< unsigned int, std::map< unsigned int, memory_symbolRef > > internal
set of variables allocated internally to the cores, classified by function id
Definition: memory.hpp:76
unsigned long long int next_base_address
it represents the next address that is available for internal allocation
Definition: memory.hpp:118
void reserve_space(unsigned long long space)
Explicitly allocate a certain space in the external memory.
Definition: memory.cpp:577
void xwrite(xml_element *node)
Writes the current memory allocation into an XML description.
Definition: memory.cpp:751
static std::string name_function(const tree_managerConstRef &tm, const unsigned int index)
Return the name of the function.
unsigned int count_non_private_internal_symbols() const
Definition: memory.cpp:273
unsigned long long int get_next_internal_base_address() const
Returns next free address of memory allocated internally but not private.
Definition: memory.cpp:604
bool null_pointer_check
when false object could be allocated starting from address 0
Definition: memory.hpp:178
std::map< unsigned int, memory_symbolRef > external
set of variables allocated outside the top module
Definition: memory.hpp:73
std::map< unsigned int, memory_symbolRef > get_function_parameters(unsigned int funID_scope) const
Return parameters allocated in register of the interface.
Definition: memory.cpp:427
std::map< unsigned int, memory_symbolRef > callSites
set of call sites for __builtin_wait_call
Definition: memory.hpp:97
bool is_parameter(unsigned int funID_scope, unsigned int var) const
Test if a variable is into the set of interface registers.
Definition: memory.cpp:386
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
const tree_nodeRef CGetTreeReindex(const unsigned int i) const
Return a tree_reindex wrapping the i-th tree_node.
std::string filename
static unsigned int get_var_alignment(const tree_managerConstRef &TM, unsigned int var)
Return the var alignment.
unsigned long long external_base_address_alignment
external address alignment
Definition: memory.hpp:169
Definition of the class representing a generic C application.
const structural_objectRef get_circ() const
Get a reference to circ field.
void add_parm_decl_stored(unsigned int var)
add a parm_decl to the set of parm_decl that has to be initialized
Definition: memory.cpp:629
Datastructure to represent a memory symbol in HLS.
mathematical utility function not provided by standard libraries
static unsigned long long int align(unsigned long long int address, unsigned long long int alignment)
STL includes.
Definition: memory.cpp:81
bool has_sds_var(unsigned int var) const
return true if the var has been classified in term of same data size relation
Definition: memory.cpp:381
bool implicit_memcpy
when true an implicit memcpy is called
Definition: memory.hpp:163
#define MEMORY_PARAMETER
std::map< unsigned int, unsigned long long int > rangesize
for each var store the address space rangesize associated with it
Definition: memory.hpp:90
bool notEQ(refcount< memory > ref) const
return true in case the current memory object and the passed one are different
Definition: memory.cpp:840
exceptions managed by PandA
CustomOrderedSet< unsigned int > private_memories
store the objects that does not need to be attached to the bus
Definition: memory.hpp:100
bool is_read_only_variable(unsigned var) const
return true when the variable is only read
Definition: memory.cpp:229
void set_sds_var(unsigned int var, bool value)
set if a variable is always accessed with the same data size or not
Definition: memory.cpp:313
bool has_external_base_address(unsigned int var) const
Check if there is a base address for the given variable.
Definition: memory.cpp:446
unsigned long long get_allocated_space() const
Returns the amount of memory allocated internally to the module.
Definition: memory.cpp:589
const tree_managerConstRef TreeM
data-structure containing tree information
Definition: memory.hpp:70
std::map< unsigned int, CustomOrderedSet< unsigned int > > source_values
ssa_names assigned to a given memory variable
Definition: memory.hpp:106
std::map< unsigned int, memory_symbolRef > get_function_vars(unsigned int funID_scope) const
Return the variables allocated within the space of a given function.
Definition: memory.cpp:417
refcount< memory > memoryRef
refcount definition of the class
Definition: memory.hpp:831
CustomOrderedSet< unsigned int > parm_decl_copied
parm_decl that has to be copied from the caller
Definition: memory.hpp:109
#define min(x, y)
virtual ~memory()
Destructor.
void add_internal_variable(unsigned int funID_scope, unsigned int var, const std::string &var_name)
Allocates a variable to the set of variables allocated internally to the given function.
Definition: memory.cpp:175
const CustomOrderedSet< unsigned int > & get_proxied_internal_variables(unsigned int funID_scope) const
return the proxied internal variables associated with the function
Definition: memory.cpp:208
unsigned long long int get_base_address(unsigned int var, unsigned int funId) const
Get the current base address of the given variable.
Definition: memory.cpp:467
unsigned long long get_external_base_address(unsigned int var) const
Get the current base address of the given variable.
Definition: memory.cpp:404
CustomOrderedSet< unsigned int > actual_parm_loaded
actual parameter that has to be loaded from a stored value
Definition: memory.hpp:115
bool is_external_variable(unsigned int var) const
Test if a variable is into the set of variables out of the top function.
Definition: memory.cpp:365
bool is_a_proxied_variable(unsigned int var) const
return true if the variable is a proxied variable
Definition: memory.cpp:219
const unsigned int & bus_addr_bitsize
Definition: memory.hpp:192
std::string GetParameter(std::string name) const
Get the value associated to parameter if it has been associated; if it has not specified returns the ...
const tree_nodeConstRef CGetTreeNode(const unsigned int i) const
std::map< unsigned int, memory_symbolRef > in_vars
set of all the internal variables
Definition: memory.hpp:87
#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.
static void add_memory_parameter(const structural_managerRef SM, const std::string &name, const std::string &value)
Adds the given memory parameter to the corresponding object.
Definition: memory.cpp:725
unsigned long long get_callSite_base_address(unsigned int var) const
Get the current base address of the given call site.
Definition: memory.cpp:392
#define max
Definition: backprop.h:17
CustomOrderedSet< unsigned int > parm_decl_stored
parm_decl storage has to be initialized from the formal parameter
Definition: memory.hpp:112
virtual void AddParameter(const std::string &name, const std::string &default_value)
Add a parameter.
unsigned long long get_allocated_parameters_memory() const
Return the total amount of memory allocated for the memory mapped parameters.
Definition: memory.cpp:594
unsigned long long get_first_address(unsigned int funId) const
Get the first address of the function address space.
Definition: memory.cpp:485
bool all_pointers_resolved
is true when all pointers are resolved statically
Definition: memory.hpp:160
unsigned long long get_rangesize(unsigned int var) const
return the address space rangesize associated with the given var
Definition: memory.cpp:571
void add_read_only_variable(unsigned var)
add a read only variable
Definition: memory.cpp:224
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
void add_private_memory(unsigned int var)
add a var that safely cannot be attached to the bus
Definition: memory.cpp:308
memory_symbolRef get_symbol(unsigned int var, unsigned int funId) const
Return the symbol associated with the given variable.
Definition: memory.cpp:553
void xwrite2(xml_element *node)
Writes the current memory allocation into an XML description.
Definition: memory.cpp:1062
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)
Definition: memory.cpp:132
unsigned long long int total_amount_of_parameter_memory
total amount of parameter memory
Definition: memory.hpp:130
const unsigned long long parameter_alignment
parameter alignment
Definition: memory.hpp:172
std::map< unsigned int, size_t > maximum_loads
define for each variable the number of loads whenever it is possible
Definition: memory.hpp:184
refcount< memory_symbol > memory_symbolRef
refcount definition of the class
unsigned long long internal_base_address_alignment
internal address alignment
Definition: memory.hpp:166
std::map< unsigned int, memory_symbolRef > params
set of all the internal parameters
Definition: memory.hpp:95
void write_to_file_formatted(const std::filesystem::path &filename)
Write the document to a file.
void add_parameter_symbol(unsigned int funID_scope, unsigned int var, const memory_symbolRef m_sym)
Allocates a parameter to the set of the interface registers.
Definition: memory.cpp:336
xml_element * create_root_node(const std::string &_name)
Creates the root node.
unsigned int maxbram_bitsize
maximum bram bitsize
Definition: memory.hpp:148
unsigned long long int get_internal_base_address(unsigned int var) const
Get the current base address of the given variable.
Definition: memory.cpp:398
bool has_parameter_base_address(unsigned int var, unsigned int funId) const
Check if there is a base address for the given parameter.
Definition: memory.cpp:451
bool is_parm_decl_stored(unsigned int var) const
return true in case the parm_decl parameter has to be initialized from the formal value ...
Definition: memory.cpp:624
bool is_parm_decl_copied(unsigned int var) const
return true in case the parm_decl parameter has to be copied from the caller
Definition: memory.cpp:614
std::map< unsigned int, CustomOrderedSet< unsigned int > > internal_variable_proxy
set of variable proxies accessed by a function
Definition: memory.hpp:79
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
void SetParameter(const std::string &name, const std::string &value)
Set a parameter value.
unsigned long long bus_data_bitsize
bus data bitsize
Definition: memory.hpp:139
Classes specification of the tree_node data structures.
bool is_private_memory(unsigned int var) const
Return true in case the variable is private.
Definition: memory.cpp:370
This file collects some utility functions and macros.
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
T compute_n_bytes(T bitsize)
This file collects some utility functions.
void add_external_variable(unsigned int var, const std::string &var_name)
Allocates a variable to the set of variables allocated outside to outermost function.
Definition: memory.cpp:286
std::map< unsigned int, size_t > maximum_references
define for each variable the number of references whenever it is possible
Definition: memory.hpp:181
unsigned long long compute_next_base_address(unsigned long long address, unsigned int var, unsigned long long int alignment) const
Compute the new base address based on the size of the given variable and align the memory as needed...
Definition: memory.cpp:154
unsigned long long bus_size_bitsize
bus size bitsize
Definition: memory.hpp:142
memory(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 long long initial_internal_address, const unsigned int &_bus_addr_bitsize)
Constructor.
Definition: memory.cpp:89
This class describes all classes used to represent a structural object.
void add_source_value(unsigned int var, unsigned int value)
add a value to the set of values written in a given memory variable
Definition: memory.cpp:318
#define WRITE_XNVM(variable, value, node)
WRITE XML Name Value Macro.
Definition: xml_helper.hpp:55
void add_parm_decl_copied(unsigned int var)
add a parm_decl to the set of parm_decl written
Definition: memory.cpp:619
Class specification of the tree_reindex support class.
bool has_base_address(unsigned int var) const
Check if there is a base address for the given variable.
Definition: memory.cpp:461
bool is_sds_var(unsigned int var) const
check if the variable is always accessed with the same data size
Definition: memory.cpp:375
CustomOrderedSet< unsigned int > read_only_vars
Definition: memory.hpp:84
#define WRITE_XVM(variable, node)
WRITE XML Value Macro. Insert a value in an XML tree.
Definition: xml_helper.hpp:51
unsigned long long int get_max_address() const
return the maximum address allocated
Definition: memory.cpp:609
bool ExistsParameter(std::string name) const
Check if a parameter has been specified.
void add_actual_parm_loaded(unsigned int var)
add an actual parameter to the set of parameter that has to be initialized from a stored value ...
Definition: memory.cpp:639
static tree_nodeConstRef CGetType(const tree_nodeConstRef &node)
Return the treenode of the type of node.
unsigned long long get_memory_address() const
Return the first memory address not yet allocated.
Definition: memory.cpp:354
bool use_unknown_addresses
Spec accesses data having an address unknown at compile time.
Definition: memory.hpp:154
CustomOrderedSet< unsigned int > need_bus
define for each variable the number of loads whenever it is possible
Definition: memory.hpp:187
unsigned long long int maximum_private_memory_size
is the maximum amount of private memory allocated
Definition: memory.hpp:124
bool has_internal_base_address(unsigned int var) const
Check if there is a base address for the given variable.
Definition: memory.cpp:441
void add_external_symbol(unsigned int var, const memory_symbolRef m_sym)
Allocates a variable to the set of variables allocated outside to outermost function.
Definition: memory.cpp:293
this class is used to manage the command-line or XML options.
CustomOrderedSet< unsigned int > proxied_variables
is the set of proxied variables
Definition: memory.hpp:82
unsigned long long int get_allocated_internal_memory() const
Returns the amount of memory allocated internally but not private.
Definition: memory.cpp:599
unsigned long long int total_amount_of_private_memory
total amount of internal memory allocated
Definition: memory.hpp:127
Some macro used to interface with the XML library.
unsigned long long get_last_address(unsigned int funId, const application_managerRef AppM) const
Get the last address of the function address space.
Definition: memory.cpp:515
Wrapper to call graph.
Class implementation of the structural_manager.
bool packed_vars
true when packed vars are used
Definition: memory.hpp:190
unsigned long long int internal_base_address_start
is the start internal address
Definition: memory.hpp:121
bool is_actual_parm_loaded(unsigned int var) const
return true in case the actual parameter has to be initialized from a stored value ...
Definition: memory.cpp:634
bool is_internal_variable(unsigned int funID_scope, unsigned int var) const
Test if a variable is allocated into the specified function.
Definition: memory.cpp:359
unsigned long long bram_bitsize
bram bitsize
Definition: memory.hpp:145
bool intern_shared_data
define if the Spec has data that can be externally accessed
Definition: memory.hpp:151
Base class for all register into datapath.
void reserve_internal_space(unsigned long long int space)
Explicitly allocate a certain space in the internal memory.
Definition: memory.cpp:583
bool has_callSite_base_address(unsigned int var) const
Check if there is a base address for the given call site.
Definition: memory.cpp:436
bool has_proxied_internal_variables(unsigned int funID_scope) const
check if the function has proxied variables
Definition: memory.cpp:214
std::map< unsigned int, memory_symbolRef > get_ext_memory_variables() const
Return variables allocated out of the top module.
Definition: memory.cpp:149
void set_internal_base_address_alignment(unsigned long long _internal_base_address_alignment)
set the internal base address alignment
Definition: memory.cpp:644
Datastructure to represent memory information in high-level synthesis.
xml_element * add_child_element(const std::string &name)
Add a child element to this node.
Definition: xml_node.cpp:54
bool unaligned_accesses
true when LOADs or STOREs perform unaligned accesses
Definition: memory.hpp:157
std::map< unsigned int, std::map< unsigned int, memory_symbolRef > > parameter
set of variables allocated in registers of the interface
Definition: memory.hpp:93
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.
void add_internal_symbol(unsigned int funID_scope, unsigned int var, const memory_symbolRef m_sym)
Allocates a variable to the set of variables allocated internally to the given function.
Definition: memory.cpp:234
unsigned long long int next_off_base_address
it represents the next address that is available to allocate a variable out of the top module ...
Definition: memory.hpp:136
std::map< unsigned int, unsigned int > same_data_size_accesses
store if a given variable is accessed always with the same data_size or not
Definition: memory.hpp:103
void add_internal_variable_proxy(unsigned int funID_scope, unsigned int var)
allocate a proxy for the variable for the specified function
Definition: memory.cpp:202
#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