PandA-2024.02
VcdSignalSelection.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) 2015-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  */
36 #include "VcdSignalSelection.hpp"
37 #include "Discrepancy.hpp"
38 #include "Parameter.hpp"
39 #include "UnfoldedFunctionInfo.hpp"
41 #include "behavioral_helper.hpp"
42 #include "call_graph.hpp"
43 #include "call_graph_manager.hpp"
44 #include "cpu_time.hpp"
45 #include "design_flow_manager.hpp"
46 #include "fu_binding.hpp"
47 #include "function_behavior.hpp"
48 #include "generic_obj.hpp"
49 #include "hls.hpp"
50 #include "hls_manager.hpp"
51 #include "language_writer.hpp"
52 #include "memory.hpp"
53 #include "reg_binding.hpp"
55 #include "string_manipulation.hpp" // for GET_CLASS
56 #include "structural_objects.hpp"
57 #include "technology_node.hpp"
58 #include "tree_helper.hpp"
59 #include "tree_manager.hpp"
60 #include "tree_reindex.hpp"
61 
63  const DesignFlowManagerConstRef _design_flow_manager)
64  : HLS_step(_parameters, _HLSMgr, _design_flow_manager, HLSFlowStep_Type::VCD_SIGNAL_SELECTION),
65  TM(_HLSMgr->get_tree_manager()),
66  Discr(HLSMgr->RDiscr),
67  present_state_name(static_cast<HDLWriter_Language>(_parameters->getOption<unsigned int>(OPT_writer_language)) ==
69  "_present_state" :
70  "present_state")
71 {
72  THROW_ASSERT(parameters->isOption(OPT_discrepancy) and parameters->getOption<bool>(OPT_discrepancy),
73  "Step " + STR(__PRETTY_FUNCTION__) + " should not be added without discrepancy");
74  THROW_ASSERT(HLSMgr->RDiscr, "Discr data structure is not correctly initialized");
75  debug_level = _parameters->get_class_debug_level(GET_CLASS(*this));
76 }
77 
79 
80 bool VcdSignalSelection::IsAddressType(const unsigned int type_index) const
81 {
82  return tree_helper::is_a_pointer(TM, type_index) or tree_helper::is_an_array(TM, type_index) or
83  (tree_helper::is_a_vector(TM, type_index) and
85 }
86 
89 {
91  switch(relationship_type)
92  {
94  {
99  break;
100  }
103  {
104  break;
105  }
106  default:
107  {
108  THROW_UNREACHABLE("");
109  break;
110  }
111  }
112  return ret;
113 }
114 
117 {
118  for(const unsigned int fun_id : reached_body_fun_ids)
119  {
120  const tree_nodeConstRef fun_decl_node = TM->CGetTreeNode(fun_id);
121  THROW_ASSERT(fun_decl_node->get_kind() == function_decl_K,
122  fun_decl_node->ToString() + " is of kind " + tree_node::GetString(fun_decl_node->get_kind()));
123  const auto* fu_dec = GetPointer<const function_decl>(fun_decl_node);
124  for(const auto& parm_decl_node : fu_dec->list_of_args)
125  {
126  THROW_ASSERT(GET_NODE(parm_decl_node)->get_kind() == parm_decl_K,
127  parm_decl_node->ToString() + " is of kind " + tree_node::GetString(parm_decl_node->get_kind()));
129  {
130  address_parameters[fun_id].insert(GET_NODE(parm_decl_node));
131  }
132  }
133  }
134  return;
135 }
136 
138  const tree_nodeConstRef& tn, const CustomUnorderedSet<unsigned int>& addr_fun_ids,
139  const CustomUnorderedMap<unsigned int, UnorderedSetStdStable<unsigned int>>& call_id_to_called_id)
140 {
141  THROW_ASSERT(tn->get_kind() == gimple_assign_K,
142  tn->ToString() + " is of kind " + tree_node::GetString(tn->get_kind()));
143  const auto* g_as_node = GetPointer<const gimple_assign>(tn);
144  /* check if the left value is an ssa_name_K */
145  const tree_nodeRef ssa_node = GET_NODE(g_as_node->op0);
146  if(ssa_node->get_kind() != ssa_name_K)
147  {
148  return;
149  }
150  // complexes and reals are never marked as addresses
151  if(tree_helper::is_real(TM, ssa_node->index) or tree_helper::is_a_complex(TM, ssa_node->index))
152  {
153  return;
154  }
155 
156  const tree_nodeConstRef rhs = GET_NODE(g_as_node->op1);
157  const auto rhs_kind = rhs->get_kind();
158  /*
159  * If the user does not specify OPT_discrepancy_no_load_pointers, all the
160  * values loaded from memory must be treated as if thy were addresses. This
161  * happens because we don't know where these data come from. Even if the load
162  * is from a memory used to store integers, we don't know if somobody used it
163  * to store a pointer, so we must treat it as if it were an address.
164  */
165  THROW_ASSERT(rhs_kind != component_ref_K and rhs_kind != array_ref_K and rhs_kind != target_mem_ref_K and
166  rhs_kind != target_mem_ref461_K,
167  "unexpected tree_node");
168  if(rhs_kind == mem_ref_K)
169  {
170  if(not parameters->isOption(OPT_discrepancy_no_load_pointers) or
171  not parameters->getOption<bool>(OPT_discrepancy_no_load_pointers))
172  {
173  Discr->address_ssa.insert(ssa_node);
174  }
175  }
176 
177  /*
178  * if this statements assign to the ssa the result of a function call, we must
179  * check if the function returns a value that can be an address. if so, the
180  * assigned ssa must be marked as address as well
181  */
182  if(rhs_kind == call_expr_K || rhs_kind == aggr_init_expr_K)
183  {
184  /*
185  * if the called function returns an address value also the ssa is marked
186  */
187  THROW_ASSERT(call_id_to_called_id.find(tn->index) != call_id_to_called_id.end(),
188  "call id " + STR(tn->index) + " does not call any function");
189  for(unsigned int i : call_id_to_called_id.at(tn->index))
190  {
191  if(addr_fun_ids.find(i) != addr_fun_ids.end())
192  {
193  Discr->address_ssa.insert(ssa_node);
194  }
195  }
196  return;
197  }
198  /*
199  * check the tree_nodeRef for the right-hand side of the assignement. if it's
200  * a cast of some pointer types, then the ssa is marked as address too
201  */
202  unsigned int rhs_type_index;
203  if(rhs_kind == nop_expr_K)
204  {
205  const auto* nop = GetPointer<const nop_expr>(rhs);
206  rhs_type_index = tree_helper::get_type_index(TM, GET_INDEX_NODE(nop->op));
207  }
208  else if(rhs_kind == convert_expr_K)
209  {
210  const auto* convert = GetPointer<const convert_expr>(rhs);
211  rhs_type_index = tree_helper::get_type_index(TM, GET_INDEX_NODE(convert->op));
212  }
213  else if(rhs_kind == view_convert_expr_K)
214  {
215  const auto* view_convert = GetPointer<const view_convert_expr>(rhs);
216  rhs_type_index = tree_helper::get_type_index(TM, GET_INDEX_NODE(view_convert->op));
217  }
218  else
219  {
220  return;
221  }
222 
223  if(IsAddressType(rhs_type_index))
224  {
225  Discr->address_ssa.insert(ssa_node);
226  }
227 
228  return;
229 }
230 
232 {
233  THROW_ASSERT(tn->get_kind() == gimple_phi_K, tn->ToString() + " is of kind " + tree_node::GetString(tn->get_kind()));
234  const gimple_phi& phi = *GetPointer<const gimple_phi>(tn);
235  auto phi_it = phi.CGetDefEdgesList().begin();
236  const auto phi_end = phi.CGetDefEdgesList().end();
237  const TreeNodeSet& address_ssa = Discr->address_ssa;
238  const auto is_address = [&address_ssa](const std::pair<tree_nodeRef, unsigned int>& p) -> bool {
239  return (GET_NODE(p.first)->get_kind() == addr_expr_K) or
240  (address_ssa.find(GET_NODE(p.first)) != address_ssa.end());
241  };
242  if(std::find_if(phi_it, phi_end, is_address) != phi_end)
243  {
244  THROW_ASSERT(GET_NODE(phi.res)->get_kind() == ssa_name_K,
245  "phi node id: " + STR(tn->index) + " result node id: " + STR(GET_NODE(phi.res)->index) + "\n");
246  Discr->address_ssa.insert(GET_NODE(phi.res));
247  }
248 }
249 
251  const CustomOrderedSet<unsigned int>& reached_body_fun_ids, const CustomUnorderedSet<unsigned int>& addr_fun_ids,
252  const CustomUnorderedMap<unsigned int, UnorderedSetStdStable<unsigned int>>& call_id_to_called_id)
253 {
254  for(const auto fid : reached_body_fun_ids)
255  {
256  const FunctionBehaviorConstRef FB = HLSMgr->CGetFunctionBehavior(fid);
257  const OpGraphConstRef op_graph = FB->CGetOpGraph(FunctionBehavior::FCFG);
259  VertexIterator vi, vi_end;
260  for(boost::tie(vi, vi_end) = boost::vertices(*op_graph); vi != vi_end; vi++)
261  {
262  const unsigned int st_tn_id = op_graph->CGetOpNodeInfo(*vi)->GetNodeId();
263  if(st_tn_id == ENTRY_ID || st_tn_id == EXIT_ID)
264  {
265  continue;
266  }
267  THROW_ASSERT(st_tn_id, "operation vertex has id = 0");
268  const tree_nodeConstRef curr_tn = TM->CGetTreeNode(st_tn_id);
269  const unsigned int assigned_tree_node_id = HLSMgr->get_produced_value(fid, *vi);
270  if(assigned_tree_node_id == 0)
271  {
272  continue;
273  }
274  const tree_nodeRef assigned_ssa_tree_node = TM->get_tree_node_const(assigned_tree_node_id);
275  if(assigned_ssa_tree_node->get_kind() != ssa_name_K)
276  {
277  continue;
278  }
279  /*
280  * if the ssa_name is never used it should be skipped. if we don't do this
281  * the vcd signal selector will try to select the output signal. but if the
282  * ssa is not used, the output wire is not placed by the interconnection and
283  * the simulator dies when it tries to find it
284  */
285  const auto* ssa = GetPointer<const ssa_name>(assigned_ssa_tree_node);
286  if(ssa->CGetUseStmts().empty())
287  {
288  Discr->ssa_to_skip.insert(assigned_ssa_tree_node);
289  if(IsAddressType(tree_helper::get_type_index(TM, assigned_tree_node_id)))
290  {
291  Discr->address_ssa.insert(assigned_ssa_tree_node);
292  }
293  continue;
294  }
295  /*
296  * Never mark an ssa as address if it is a complex or floating point.
297  * This assumption is kind of arbitrary because if somebody does some dirty
298  * tricks with pointers it is possible to fool the checks in this way.
299  * However, dirty pointer tricks with floating points and with complex values
300  * are more rare than with integers, so for now I make this assumption.
301  */
302  if(tree_helper::is_a_complex(TM, assigned_tree_node_id) or tree_helper::is_real(TM, assigned_tree_node_id))
303  {
304  continue;
305  }
306  /*
307  * check the type of the ssa variable.
308  */
309  if(IsAddressType(tree_helper::get_type_index(TM, assigned_tree_node_id)))
310  {
311  Discr->address_ssa.insert(assigned_ssa_tree_node);
312  continue;
313  }
314  if(curr_tn->get_kind() == gimple_assign_K)
315  {
316  InitialSsaIsAddress(curr_tn, addr_fun_ids, call_id_to_called_id);
317  }
318  else if(curr_tn->get_kind() == gimple_phi_K)
319  {
320  InitialPhiResIsAddress(curr_tn);
321  }
322  }
323  }
324  return;
325 }
326 
328  const TreeNodeSet& address_parameters)
329 {
330  auto ssause_it = used_ssa.begin();
331  const auto ssause_end = used_ssa.end();
332  for(; ssause_it != ssause_end; ++ssause_it)
333  {
334  THROW_ASSERT(ssause_it->first->get_kind() == tree_reindex_K,
335  ssause_it->first->ToString() + " is of kind " + tree_node::GetString(ssause_it->first->get_kind()));
336  const tree_nodeRef ssa_node = GET_NODE(ssause_it->first);
337  const auto* ssa = GetPointer<const ssa_name>(ssa_node);
338  if(!ssa->var)
339  {
340  continue;
341  }
342  THROW_ASSERT(ssa->var->get_kind() == tree_reindex_K,
343  ssa->var->ToString() + " is of kind " + tree_node::GetString(ssa->var->get_kind()));
344  if(address_parameters.find(ssa->var) != address_parameters.end())
345  {
346  const auto def = ssa->CGetDefStmts();
347  THROW_ASSERT(not def.empty(), ssa_node->ToString() + " has no def_stmts");
348  if(def.size() == 1 and ((GET_NODE((*def.begin()))->get_kind() == gimple_nop_K) or ssa->volatile_flag))
349  {
350  Discr->address_ssa.insert(ssa_node);
351  Discr->ssa_to_skip.insert(ssa_node);
352  }
353  }
354  }
355  return;
356 }
357 
359  const CustomUnorderedMap<unsigned int, TreeNodeSet>& address_parameters,
360  const CustomOrderedSet<unsigned int>& reached_body_fun_ids)
361 {
362  for(const auto fid : reached_body_fun_ids)
363  {
364  const CustomUnorderedMap<unsigned int, TreeNodeSet>::const_iterator addrp_it = address_parameters.find(fid);
365  bool has_addr_param = (addrp_it != address_parameters.end());
366  if(not has_addr_param)
367  {
368  continue;
369  }
370  const FunctionBehaviorConstRef FB = HLSMgr->CGetFunctionBehavior(fid);
371  const OpGraphConstRef op_graph = FB->CGetOpGraph(FunctionBehavior::FCFG);
373  VertexIterator vi, vi_end;
374  for(boost::tie(vi, vi_end) = boost::vertices(*op_graph); vi != vi_end; vi++)
375  {
376  const OpNodeInfoConstRef op_info = op_graph->CGetOpNodeInfo(*vi);
377  const unsigned int st_tn_id = op_info->GetNodeId();
378  if(st_tn_id == ENTRY_ID || st_tn_id == EXIT_ID)
379  {
380  continue;
381  }
382  THROW_ASSERT(st_tn_id, "operation vertex has id = 0");
383  const tree_nodeConstRef curr_tn = TM->CGetTreeNode(st_tn_id);
384  if(curr_tn->get_kind() == gimple_assign_K)
385  {
386  const auto* g_as_node = GetPointer<const gimple_assign>(curr_tn);
387  const TreeNodeMap<size_t> used_ssa = tree_helper::ComputeSsaUses(g_as_node->op1);
388  SingleStepPropagateParamToSsa(used_ssa, addrp_it->second);
389  }
390  else
391  {
392  const TreeNodeMap<size_t> used_ssa = tree_helper::ComputeSsaUses(op_info->node);
393  SingleStepPropagateParamToSsa(used_ssa, addrp_it->second);
394  }
395  }
396  }
397  return;
398 }
399 
401 {
402  THROW_ASSERT(curr_tn->get_kind() == tree_reindex_K,
403  curr_tn->ToString() + " is of kind " + tree_node::GetString(curr_tn->get_kind()));
404  const tree_nodeConstRef tn = GET_NODE(curr_tn);
405  if(tn->get_kind() == gimple_assign_K)
406  {
407  const auto* g_as_node = GetPointer<const gimple_assign>(tn);
408  /* check if the left value is an ssa_name_K */
409  const tree_nodeRef ssa_node = GET_NODE(g_as_node->op0);
410  if(tree_helper::is_real(TM, ssa_node->index) or tree_helper::is_a_complex(TM, ssa_node->index))
411  {
412  return;
413  }
414  if(ssa_node->get_kind() == ssa_name_K)
415  {
416  const tree_nodeConstRef rhs = GET_NODE(g_as_node->op1);
417  const auto rhs_kind = rhs->get_kind();
418 
419  const bool rhs_is_comparison = rhs_kind == lt_expr_K || rhs_kind == le_expr_K || rhs_kind == gt_expr_K ||
420  rhs_kind == ge_expr_K || rhs_kind == eq_expr_K || rhs_kind == ne_expr_K ||
421  rhs_kind == unordered_expr_K || rhs_kind == ordered_expr_K ||
422  rhs_kind == unlt_expr_K || rhs_kind == unle_expr_K || rhs_kind == ungt_expr_K ||
423  rhs_kind == unge_expr_K || rhs_kind == uneq_expr_K || rhs_kind == ltgt_expr_K;
424 
425  bool is_a_vector_bitfield = false;
426  if(rhs_kind == bit_field_ref_K)
427  {
428  const auto* bfr = GetPointer<const bit_field_ref>(rhs);
430  {
431  is_a_vector_bitfield = true;
432  }
433  }
434 
435  bool rhs_is_load_candidate =
436  (rhs_kind == bit_field_ref_K && !is_a_vector_bitfield) || rhs_kind == component_ref_K ||
437  rhs_kind == indirect_ref_K || rhs_kind == misaligned_indirect_ref_K || rhs_kind == mem_ref_K ||
438  rhs_kind == array_ref_K || rhs_kind == target_mem_ref_K ||
439  rhs_kind == target_mem_ref461_K /*|| rhs_kind == realpart_expr_K || rhs_kind == imagpart_expr_K*/;
440 
441  if(rhs_kind == view_convert_expr_K)
442  {
443  const auto* vc = GetPointer<const view_convert_expr>(rhs);
444  const auto vc_kind = GET_CONST_NODE(tree_helper::CGetType(vc->op))->get_kind();
445  if(vc_kind == record_type_K || vc_kind == union_type_K)
446  {
447  rhs_is_load_candidate = true;
448  }
449  if(vc_kind == array_type_K && ssa_node->get_kind() == vector_type_K)
450  {
451  rhs_is_load_candidate = true;
452  }
453  }
454 
455  if((not rhs_is_comparison) and (not rhs_is_load_candidate) and not(rhs_kind == call_expr_K))
456  {
457  Discr->address_ssa.insert(ssa_node);
458  }
459  }
460  }
461  else if(tn->get_kind() == gimple_phi_K)
462  {
463  const gimple_phi& phi = *GetPointer<const gimple_phi>(tn);
464  auto phi_it = phi.CGetDefEdgesList().begin();
465  const auto phi_end = phi.CGetDefEdgesList().end();
466  const TreeNodeSet& address_ssa = Discr->address_ssa;
467  const auto is_address = [&address_ssa](const std::pair<tree_nodeRef, unsigned int>& p) -> bool {
468  return (GET_NODE(p.first)->get_kind() == addr_expr_K) or
469  (address_ssa.find(GET_NODE(p.first)) != address_ssa.end());
470  };
471  if(std::find_if(phi_it, phi_end, is_address) != phi_end)
472  {
473  THROW_ASSERT(GET_NODE(phi.res)->get_kind() == ssa_name_K,
474  "phi node id: " + STR(tn->index) + " result node id: " + STR(GET_NODE(phi.res)->index) + "\n");
475  Discr->address_ssa.insert(GET_NODE(phi.res));
476  }
477  }
478  return;
479 }
480 
482 {
483  size_t previous_address_ssa_size;
484  do
485  {
486  previous_address_ssa_size = static_cast<size_t>(Discr->address_ssa.size());
487  for(const auto& addr : Discr->address_ssa)
488  {
489  THROW_ASSERT(addr->get_kind() == ssa_name_K,
490  addr->ToString() + " is of kind " + tree_node::GetString(addr->get_kind()));
491  for(const auto& stmt_using_ssa : GetPointer<const ssa_name>(addr)->CGetUseStmts())
492  {
493  SingleStepPropagateAddrSsa(stmt_using_ssa.first);
494  }
495  }
496  } while(previous_address_ssa_size != static_cast<size_t>(Discr->address_ssa.size()));
497  return;
498 }
499 
501  CustomUnorderedSet<unsigned int>& addr_fun_ids)
502 {
503  for(const unsigned int i : reached_body_functions)
504  {
505  if(addr_fun_ids.find(i) != addr_fun_ids.end())
506  {
507  continue;
508  }
509  const FunctionBehaviorConstRef FB = HLSMgr->CGetFunctionBehavior(i);
510  const OpGraphConstRef op_graph = FB->CGetOpGraph(FunctionBehavior::FCFG);
511  const vertex exit_vertex = op_graph->CGetOpGraphInfo()->exit_vertex;
512  for(const EdgeDescriptor& edge : op_graph->CGetInEdges(exit_vertex))
513  {
514  const vertex& op = boost::source(edge, *op_graph);
515  const unsigned int node_id = op_graph->CGetOpNodeInfo(op)->GetNodeId();
516  if(node_id == ENTRY_ID or node_id == EXIT_ID)
517  {
518  continue;
519  }
520  const tree_nodeConstRef tn = TM->CGetTreeNode(node_id);
521  if(tn->get_kind() == gimple_return_K)
522  {
523  const auto* gr = GetPointer<const gimple_return>(tn);
524  if((gr->op != nullptr) && (IsAddressType(tree_helper::get_type_index(TM, GET_INDEX_NODE(gr->op))) ||
525  ((GET_NODE(gr->op)->get_kind() == ssa_name_K) &&
526  (Discr->address_ssa.find(GET_NODE(gr->op)) != Discr->address_ssa.end()))))
527  {
528  addr_fun_ids.insert(i);
529  break;
530  }
531  }
532  }
533  }
534 }
535 
537  const CustomUnorderedMap<unsigned int, TreeNodeSet>& address_parameters,
538  const CustomOrderedSet<unsigned int>& reached_body_functions, CustomUnorderedSet<unsigned int>& addr_fun_ids)
539 {
540  PropagateAddrParamToSsa(address_parameters, reached_body_functions);
542  DetectInvalidReturns(reached_body_functions, addr_fun_ids);
543  return;
544 }
545 
548  const CustomOrderedSet<unsigned int>& reached_body_functions, const CustomUnorderedSet<unsigned int>& addr_fun_ids,
549  const CustomUnorderedMap<unsigned int, UnorderedSetStdStable<unsigned int>>& fu_id_to_call_ids,
550  const CustomUnorderedMap<unsigned int, UnorderedSetStdStable<unsigned int>>& call_id_to_called_id)
551 {
552  for(const unsigned int caller_fun_id : reached_body_functions)
553  {
554  const FunctionBehaviorConstRef FB = HLSMgr->CGetFunctionBehavior(caller_fun_id);
555  const OpGraphConstRef op_graph = FB->CGetOpGraph(FunctionBehavior::FCFG);
557  THROW_ASSERT(fu_id_to_call_ids.find(caller_fun_id) != fu_id_to_call_ids.end(),
558  "caller_id = " + STR(caller_fun_id));
559  for(const unsigned int callid : fu_id_to_call_ids.at(caller_fun_id))
560  {
561  THROW_ASSERT(call_id_to_called_id.find(callid) != call_id_to_called_id.end(), "callid = " + STR(callid));
562  for(const unsigned int called_id : call_id_to_called_id.at(callid))
563  {
564  /*
565  * if this an artificial call (it happens only for memcpy),
566  * then we don't cross propagate inside
567  */
568  if(callid == 0)
569  {
570  THROW_ASSERT(HLSMgr->CGetFunctionBehavior(called_id)->CGetBehavioralHelper()->get_function_name() ==
571  MEMCPY,
572  "artificial calls to " +
573  HLSMgr->CGetFunctionBehavior(called_id)->CGetBehavioralHelper()->get_function_name() +
574  " should not happen");
575  continue;
576  }
577  /*
578  * Cross propagation downwards, from return statements of the called
579  * function to the ssa of the caller.
580  * If the return value of an address function is assigned to an ssa,
581  * then the ssa itself must be marked as address
582  */
583  const tree_nodeConstRef call_node = TM->CGetTreeNode(callid);
584  const BehavioralHelperConstRef called_BH = HLSMgr->CGetFunctionBehavior(called_id)->CGetBehavioralHelper();
585  if(call_node->get_kind() == gimple_assign_K)
586  {
587  const auto* g_as = GetPointer<const gimple_assign>(call_node);
588  const tree_nodeRef ssa_node = GET_NODE(g_as->op0);
589  const tree_nodeConstRef rhs = GET_NODE(g_as->op1);
590  if(ssa_node->get_kind() == ssa_name_K and
591  (rhs->get_kind() == call_expr_K || rhs->get_kind() == aggr_init_expr_K))
592  {
593  /*
594  * if the called function returns an address value the ssa is an address
595  */
596  if(addr_fun_ids.find(called_id) != addr_fun_ids.end())
597  {
598  Discr->address_ssa.insert(ssa_node);
599  continue;
600  }
601  /*
602  * don't check the return values of the open() system call,
603  * because they are integers representing file descriptors and
604  * for this reason they cannot be compared to values in HDL
605  */
606  if(called_BH->get_function_name() == "open" and called_BH->is_operating_system_function(called_id))
607  {
608  Discr->ssa_to_skip.insert(ssa_node);
609  }
610  }
611  }
612 
613  if(not called_BH->has_implementation() or not called_BH->function_has_to_be_printed(called_id))
614  {
615  /*
616  * also don't propagate inside functions without body
617  */
618  continue;
619  }
620  /*
621  * Cross propagation downwards, from ssa of the caller function to the
622  * parameters of the called function. If a function is called passing
623  * as parameter an address ssa, then the parameter itself is marked as
624  * representing address
625  */
626  if(op_graph->CGetOpGraphInfo()->tree_node_to_operation.find(callid) ==
627  op_graph->CGetOpGraphInfo()->tree_node_to_operation.end())
628  {
629  THROW_WARNING("cannot find call for interprocedural address propagation:\n\t"
630  "caller id = " +
631  STR(caller_fun_id) +
632  "\n\t"
633  "caller name = " +
634  BH->get_function_name() +
635  "\n\t"
636  "called id = " +
637  STR(called_id) +
638  "\n\t"
639  "called name = " +
640  called_BH->get_function_name() +
641  "\n\t"
642  "call id " +
643  STR(callid) + "\ncall was probably removed by dead code elimination\n");
644  return;
645  }
646  /*
647  * retrieve the OpNodeInfo related to the tree node corresponding to
648  * the call id
649  */
650  const OpNodeInfoConstRef callopinfo =
651  op_graph->CGetOpNodeInfo(op_graph->CGetOpGraphInfo()->tree_node_to_operation.at(callid));
652  if(callopinfo->called.size() == 0)
653  {
654  continue;
655  }
656  THROW_ASSERT(callopinfo->called.size() == 1,
657  "call id " + STR(callid) + " called.size() = " + STR(callopinfo->called.size()));
658  /*
659  * now we analyze two different function declarations.
660  * called_fun_decl_node is the fun_decl of the function called
661  * according to the call graph. directly_called_fun_decl_node is the
662  * fun_decl of the function called according to the tree
663  * representation. They may not be the same only in one case: when
664  * there is an indirect call (through function pointers). In this
665  * case the call graph has the correct information on the real
666  * called function, while the tree representation has a call to
667  * __builtin_wait_call(). we retrieve both the declaration to tell
668  * the indirect call apart and propagate correctly the parameters
669  */
670  const unsigned int direct_called_id = *callopinfo->called.begin();
671  const tree_nodeConstRef direct_called_fun_decl_node = TM->CGetTreeNode(direct_called_id);
672 #if HAVE_ASSERTS
673  const auto* direct_fu_dec = GetPointer<const function_decl>(direct_called_fun_decl_node);
674 #endif
675  const tree_nodeConstRef called_fun_decl_node = TM->CGetTreeNode(called_id);
676  const auto* fu_dec = GetPointer<const function_decl>(called_fun_decl_node);
677  std::list<unsigned int>::const_iterator par_id_it, par_id_end;
678  if(called_id == direct_called_id)
679  {
680  /* it's a direct call */
681  THROW_ASSERT(called_BH->is_var_args() or
682  fu_dec->list_of_args.size() == callopinfo->actual_parameters.size() or
683  callopinfo->actual_parameters.empty(),
684  "fun decl " + STR(called_fun_decl_node->index) +
685  ", "
686  "call id " +
687  STR(callid) + ", called id " + STR(called_id) +
688  "\n"
689  "list_of_args.size() = " +
690  STR(fu_dec->list_of_args.size()) +
691  ", "
692  "actual_parameters.size() = " +
693  STR(callopinfo->actual_parameters.size()) + "\n");
694  par_id_it = callopinfo->actual_parameters.cbegin();
695  par_id_end = callopinfo->actual_parameters.cend();
696  }
697  else
698  {
699  /* it's indirect call */
700  THROW_ASSERT(GetPointer<const identifier_node>(GET_NODE(direct_fu_dec->name))->strg == BUILTIN_WAIT_CALL,
701  GetPointer<const identifier_node>(GET_NODE(direct_fu_dec->name))->strg +
702  " called_id=" + STR(called_id) + " direct_called_id=" + STR(direct_called_id));
703  THROW_ASSERT(callopinfo->actual_parameters.size() == fu_dec->list_of_args.size() + 2 or
704  callopinfo->actual_parameters.size() == fu_dec->list_of_args.size() + 3,
705  "fun decl " + STR(called_fun_decl_node->index) +
706  ", "
707  "call id " +
708  STR(callid) + ", called id " + STR(called_id) +
709  "\n"
710  "list_of_args.size() = " +
711  STR(fu_dec->list_of_args.size()) +
712  ", "
713  "actual_parameters.size() = " +
714  STR(callopinfo->actual_parameters.size()) + "\n");
715  par_id_it = std::next(callopinfo->actual_parameters.cbegin(), 2);
716  par_id_end = par_id_it;
717  std::advance(par_id_end, fu_dec->list_of_args.size());
718  }
719  auto par_decl_it = fu_dec->list_of_args.cbegin();
720  const auto par_decl_end = fu_dec->list_of_args.cend();
721  for(; (par_id_it != par_id_end) and (par_decl_it != par_decl_end); ++par_id_it, ++par_decl_it)
722  {
723  const tree_nodeRef ssa_node = TM->GetTreeNode(*par_id_it);
724  if(ssa_node->get_kind() == ssa_name_K)
725  {
726  if(Discr->address_ssa.find(ssa_node) != Discr->address_ssa.end())
727  {
728  /*
729  * the function called in callop was called with an argument
730  * representing an address. we have to propagate this
731  * information in the called function
732  */
733  address_parameters[called_id].insert(GET_NODE(*par_decl_it));
734  }
735  }
736  }
737  }
738  }
739  }
740  return;
741 }
742 
744  const CustomUnorderedMap<unsigned int, UnorderedSetStdStable<unsigned int>>& fu_id_to_call_ids,
745  const CustomUnorderedMap<unsigned int, UnorderedSetStdStable<unsigned int>>& call_id_to_called_id)
746 {
747  const CallGraphManagerConstRef CGMan = HLSMgr->CGetCallGraphManager();
748  const CallGraphConstRef cg = CGMan->CGetCallGraph();
749 
750  /*
751  * initialize the set of fun_ids representing an address
752  */
754  const auto reached_body_fun_ids = CGMan->GetReachedBodyFunctions();
755  for(auto f_id : reached_body_fun_ids)
756  {
757  const FunctionBehaviorConstRef FB = HLSMgr->CGetFunctionBehavior(f_id);
759  const unsigned int return_type_index = BH->GetFunctionReturnType(f_id);
760  if(return_type_index and IsAddressType(return_type_index))
761  {
762  addr_fun_ids.insert(f_id);
763  }
764  }
765 
766  /*
767  * initialize the parameters representing addresses for every reached functions.
768  */
770  SelectInitialAddrParam(reached_body_fun_ids, address_parameters);
771  /*
772  * get the initial ssa_name representing addresses for every function.
773  * these are basically in the following cathegories:
774  * - variables representing addresses (pointers, arrays, vectors)
775  * - integer variables resulting from pointers casted to integer
776  * - ssa_name referred to a function's parameter marked as address
777  * - ssa_name to which is assigned the return value of a function returning an address
778  * also marks ssa to skip if they are not used
779  */
780  SelectInitialSsa(reached_body_fun_ids, addr_fun_ids, call_id_to_called_id);
781  /*
782  * now we have the ssas representing addresses. we have to propagate the information to all the
783  * other statements which use the ssa to skip, in the same function and across function calls
784  */
785  InProcedurePropagateAddr(address_parameters, reached_body_fun_ids, addr_fun_ids);
786 
787  size_t previous_address_ssa_n;
788  do
789  {
790  previous_address_ssa_n = static_cast<size_t>(Discr->address_ssa.size());
791  /*
792  * now we have to propagate addresses across the functional units. this is
793  * necessary because we can have for example a function taking an integer
794  * argument wich is called passing to it a pointer casted to integer. if this
795  * happens the InProcedurePropagateAddr is not enough.
796  */
797  CrossPropagateAddrSsa(address_parameters, reached_body_fun_ids, addr_fun_ids, fu_id_to_call_ids,
798  call_id_to_called_id);
799  /*
800  * then we have to propagate again internally to the procedures
801  */
802  InProcedurePropagateAddr(address_parameters, reached_body_fun_ids, addr_fun_ids);
803  } while(previous_address_ssa_n != static_cast<size_t>(Discr->address_ssa.size()));
804  return;
805 }
806 
808  CustomUnorderedMap<unsigned int, UnorderedSetStdStable<std::string>>& fun_id_to_sig_names) const
809 {
810  const auto& fun_with_body = HLSMgr->CGetCallGraphManager()->GetReachedBodyFunctions();
811  for(const unsigned int f_id : fun_with_body)
812  {
813  const auto FB = HLSMgr->CGetFunctionBehavior(f_id);
814  /*
815  * if the function is not printed in C there's no need to select signals
816  * in vcd, because there will not be C assignments to compare them with
817  */
818  if(!FB->CGetBehavioralHelper()->has_implementation() ||
819  !FB->CGetBehavioralHelper()->function_has_to_be_printed(f_id))
820  {
821  continue;
822  }
823  fun_id_to_sig_names[f_id];
824  // get the opgraph and information on binding and allocation of this function
825  const auto op_graph = FB->CGetOpGraph(FunctionBehavior::FCFG);
826  const auto& fu_bind = HLSMgr->get_HLS(f_id)->Rfu;
827  const auto& alloc_info = HLSMgr->get_HLS(f_id)->allocation_information;
828  VertexIterator op_vi, op_vi_end;
829  // loop on the opgraph
830  for(boost::tie(op_vi, op_vi_end) = boost::vertices(*op_graph); op_vi != op_vi_end; op_vi++)
831  {
832  const auto op_node_id = op_graph->CGetOpNodeInfo(*op_vi)->GetNodeId();
833  if(op_node_id == ENTRY_ID || op_node_id == EXIT_ID)
834  {
835  continue;
836  }
837  const auto assigned_tree_node_id = HLSMgr->get_produced_value(f_id, *op_vi);
838  if(assigned_tree_node_id == 0)
839  {
840  continue;
841  }
842  const auto assigned_var_tree_node = TM->GetTreeNode(assigned_tree_node_id);
843  if(assigned_var_tree_node->get_kind() != ssa_name_K || Discr->ssa_to_skip.count(assigned_var_tree_node))
844  {
845  continue;
846  }
847  const auto op_node = TM->CGetTreeNode(op_node_id);
848  if(op_node->get_kind() == gimple_assign_K)
849  {
850  const auto fu_type_id = fu_bind->get_assign(*op_vi);
851  const auto fu_instance_id = fu_bind->get_index(*op_vi);
852  auto to_select = "out_" + fu_bind->get_fu_name(*op_vi) + "_i" + STR(fu_bind->get_index(*op_vi)) + "_";
853 
854  if(alloc_info->is_direct_access_memory_unit(fu_type_id) && alloc_info->is_memory_unit(fu_type_id))
855  {
856  to_select += "array_" + STR(alloc_info->get_memory_var(fu_type_id)) + "_" +
857  STR(fu_bind->get_index(*op_vi) / alloc_info->get_number_channels(fu_type_id));
858  }
859  else if((alloc_info->is_direct_proxy_memory_unit(fu_type_id)) ||
860  alloc_info->is_indirect_access_memory_unit(fu_type_id))
861  {
862  to_select += fu_bind->get_fu_name(*op_vi) + "_i" +
863  STR(fu_bind->get_index(*op_vi) / alloc_info->get_number_channels(fu_type_id));
864  }
865  else if(alloc_info->is_proxy_wrapped_unit(fu_type_id))
866  {
867  const auto fu_unit_name = fu_bind->get_fu_name(*op_vi);
868  if(starts_with(fu_unit_name, WRAPPED_PROXY_PREFIX))
869  {
870  to_select += alloc_info->get_fu_name(fu_type_id).first.substr(sizeof(WRAPPED_PROXY_PREFIX) - 1);
871  }
872  else
873  {
874  to_select += fu_unit_name;
875  }
876  to_select += "_instance";
877  }
878  else if(alloc_info->get_number_channels(fu_type_id) > 0)
879  {
880  to_select += fu_bind->get_fu_name(*op_vi) + "_i" +
881  STR(fu_bind->get_index(*op_vi) / alloc_info->get_number_channels(fu_type_id));
882  }
883  else if(fu_bind->get_operations(fu_type_id, fu_instance_id).size() == 1)
884  {
885  to_select += "fu_" + GET_NAME(op_graph, *op_vi);
886  }
887  else
888  {
889  to_select += fu_bind->get_fu_name(*op_vi) + "_i" + STR(fu_bind->get_index(*op_vi));
890  }
891  Discr->opid_to_outsignal[op_node_id] = to_select;
892  fun_id_to_sig_names[f_id].insert(to_select);
893  }
894  else if(op_node->get_kind() == gimple_phi_K)
895  {
896  const auto phi = GetPointerS<const gimple_phi>(op_node);
897  if(!phi->virtual_flag)
898  {
899  const auto& storage_val_info = HLSMgr->get_HLS(f_id)->storage_value_information;
900  THROW_ASSERT(storage_val_info->is_a_storage_value(nullptr, assigned_tree_node_id),
901  " variable " +
902  HLSMgr->CGetFunctionBehavior(f_id)->CGetBehavioralHelper()->PrintVariable(
903  assigned_tree_node_id) +
904  " with tree node index " + STR(assigned_tree_node_id) + " has to be a storage value");
905  const auto storage_index = storage_val_info->get_storage_value_index(nullptr, assigned_tree_node_id);
906  const auto& regbind = HLSMgr->get_HLS(f_id)->Rreg;
907  const auto reg_name = regbind->get(regbind->get_register(storage_index))->get_string();
908  const auto reg_outsig_name = "out_" + reg_name + "_" + reg_name;
909  fun_id_to_sig_names[f_id].insert(reg_outsig_name);
910  Discr->opid_to_outsignal[op_node_id] = reg_outsig_name;
911  const auto reg_wrenable_sig_name = "wrenable_" + reg_name;
912  fun_id_to_sig_names[f_id].insert(reg_wrenable_sig_name);
913  }
914  }
915  }
916  }
917 }
918 
920 {
921  THROW_ASSERT(Discr, "Discr data structure is not correctly initialized");
922  /* select the ssa representing addresses and ssa to skip in discrepancy analysis */
923  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "-->Selecting discrepancy variables");
924  SelectAddrSsa(Discr->call_sites_info->fu_id_to_call_ids, Discr->call_sites_info->call_id_to_called_id);
925  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "<--Selected discrepancy variables");
926  /* Calculate the internal signal names for every function */
927  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "-->Selecting internal signals in functions");
929  SelectInternalSignals(fun_ids_to_local_sig_names);
930  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "<--Selected internal signals in functions");
931  // helper strings
932  const std::string controller_str = "Controller_i" + STR(HIERARCHY_SEPARATOR);
933  const std::string datapath_str = "Datapath_i" + STR(HIERARCHY_SEPARATOR);
934  /* generate the scoped signal names and insert them in the selected signals*/
935  for(const auto& vs : Discr->unfolded_v_to_scope)
936  {
937  const unsigned int f_id = Cget_node_info<UnfoldedFunctionInfo>(vs.first, Discr->DiscrepancyCallGraph)->f_id;
938  const BehavioralHelperConstRef BH =
939  Cget_node_info<UnfoldedFunctionInfo>(vs.first, Discr->DiscrepancyCallGraph)->behavior->CGetBehavioralHelper();
940  if(not BH->has_implementation() or not BH->function_has_to_be_printed(f_id))
941  {
942  continue;
943  }
944  const std::string& scope = vs.second;
945  auto& datapath_scope = Discr->selected_vcd_signals[scope + datapath_str];
946  auto& controller_scope = Discr->selected_vcd_signals[scope + controller_str];
947  THROW_ASSERT(not controller_scope.empty() or datapath_scope.empty(),
948  "controller_scope size " + STR(controller_scope.size()) + " datapath_scope size " +
949  STR(datapath_scope.size()));
950  if(not controller_scope.empty())
951  { // this scope was already added by another vertex
952  continue;
953  }
954  // select start, done and present_state signals in the fsm
955  controller_scope.insert(START_PORT_NAME);
956  controller_scope.insert(DONE_PORT_NAME);
957  controller_scope.insert(present_state_name);
958  // select the clock signal (only in the root function)
959  if(vs.first == Discr->unfolded_root_v)
960  {
961  controller_scope.insert(CLOCK_PORT_NAME);
962  }
963  /*
964  * if the current function was not included with --discrepancy-only we're
965  * done and we don't need to add the signals in the datapath.
966  * the signals for the controller were necessary anyway because they are
967  * used to reconstruct the sequence of events, the clock, and the duration
968  * of the unbounded functions
969  */
970  if(parameters->isOption(OPT_discrepancy_only))
971  {
972  const auto discrepancy_functions = parameters->getOption<CustomSet<std::string>>(OPT_discrepancy_only);
973  std::string fu_name = BH->get_function_name();
974  if(not discrepancy_functions.empty() and discrepancy_functions.find(fu_name) == discrepancy_functions.end())
975  {
976  continue;
977  }
978  }
979  // select local signals in the datapath
980  THROW_ASSERT(fun_ids_to_local_sig_names.find(f_id) != fun_ids_to_local_sig_names.end(), "f_id = " + STR(f_id));
981  for(const auto& local_sig_name : fun_ids_to_local_sig_names.at(f_id))
982  {
983  datapath_scope.insert(local_sig_name);
984  }
985  }
986 #ifndef NDEBUG
988  {
989  PRINT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "Selected vcd signals");
990  for(const auto& sig_scope : Discr->selected_vcd_signals)
991  {
992  for(const auto& sig_name : sig_scope.second)
993  {
994  PRINT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "SIGNAL: " + sig_scope.first + sig_name);
995  }
996  }
997  }
998 #endif
999 
1000  std::size_t pointers_n = 0;
1001  std::size_t fully_resolved_n = 0;
1002  for(const auto& s : Discr->address_ssa)
1003  {
1004  const unsigned int ssa_index = s->index;
1005  const auto* ssa = GetPointer<const ssa_name>(s);
1006  if(ssa and IsAddressType(tree_helper::get_type_index(TM, ssa_index)))
1007  {
1008  pointers_n++;
1009  const unsigned int ssa_base_index = tree_helper::get_base_index(TM, ssa_index);
1010  if((ssa_base_index != 0 and HLSMgr->Rmem->has_base_address(ssa_base_index)) or
1011  ssa->use_set->is_fully_resolved())
1012  {
1013  fully_resolved_n++;
1014  }
1015  }
1016  else
1017  {
1018  continue;
1019  }
1020  }
1022  "DISCREPANCY RESOLVED: " + STR(fully_resolved_n) + "/" + STR(pointers_n));
1024 }
1025 
1027 {
1028  return true;
1029 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
OpEdgeSet CGetInEdges(const vertex v) const
Return the edge ingoing in a vertex.
Definition: op_graph.cpp:388
const HLS_managerRef HLSMgr
information about all the HLS synthesis
Definition: hls_step.hpp:205
const DefEdgeList & CGetDefEdgesList() const
Return the list of def edges.
Definition: tree_node.cpp:1011
void PropagateAddrSsa()
Propagates the information on the ssa representing addresses across all the ssa in the functions with...
Data structure representing the entire HLS information.
absl::node_hash_set< _Value, _Hash, _Pred, _Alloc > UnorderedSetStdStable
Definition: custom_set.hpp:215
static unsigned int GetElements(const tree_managerConstRef &TM, const unsigned int index)
Given an array or a vector return the element type.
#define MEMCPY
constant string identifying the operation performed when two objects are memcopied.
Definition: op_graph.hpp:310
#define PRINT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
std::string ToString() const
Print this node as string in gimple format.
#define DEBUG_LEVEL_PEDANTIC
very verbose debugging print is performed.
#define START_PORT_NAME
#define GET_CLASS(obj)
Macro returning the actual type of an object.
std::string get_function_name() const
Return the name of the function.
const int output_level
The output level.
static bool is_real(const tree_managerConstRef &TM, const unsigned int index)
Return true if the treenode is of real type.
void SelectInternalSignals(CustomUnorderedMap< unsigned int, UnorderedSetStdStable< std::string >> &fun_id_to_sig_names) const
RelationshipType
The relationship type.
Source must be executed to satisfy target.
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
~VcdSignalSelection() override
Destructor.
static std::string GetString(const enum kind k)
Given a kind, return the corresponding string.
Definition: tree_node.cpp:120
#define GET_NAME(data, vertex_index)
Helper macro returning the name associated with a node.
virtual bool is_var_args() const
Returns true if this function is of var args type.
#define BUILTIN_WAIT_CALL
constant defining the builtin wait call intrinsic function
Definition: op_graph.hpp:358
#define GET_INDEX_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:361
VcdSignalSelection(const ParameterConstRef _parameters, const HLS_managerRef HLSMgr, const DesignFlowManagerConstRef design_flow_manager)
Constructor.
static unsigned int get_type_index(const tree_managerConstRef &TM, const unsigned int index, long long int &vec_size, bool &is_a_pointer, bool &is_a_function)
Return the treenode index of the type of index.
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
Include a set of utilities used to manage CPU time measures.
bool has_implementation() const
Return true if function has implementation.
tree_nodeRef res
res is the new SSA_NAME node created by the PHI node.
Definition: tree_node.hpp:3772
virtual enum kind get_kind() const =0
Virtual function returning the type of the actual class.
#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.
HDLWriter_Language
Base class for all resources into datapath.
#define CLOCK_PORT_NAME
standard name for ports
virtual bool is_operating_system_function(const unsigned int obj) const
Return true if function is an operating system function.
const OpNodeInfoConstRef CGetOpNodeInfo(const vertex node) const
Returns the info associated with a node.
Definition: op_graph.hpp:843
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
bool starts_with(const std::string &str, const std::string &pattern)
void SingleStepPropagateAddrSsa(const tree_nodeRef &curr_tn)
Single step used in the loop of PropagateAddrSsa()
This struct specifies the gimple_phi node.
Definition: tree_node.hpp:3742
Data structure used to store the register binding of variables.
#define EXIT_ID
constant used to represent tree node index of exit operation
Definition: op_graph.hpp:81
absl::flat_hash_map< T, U, Hash, Eq, Alloc > CustomUnorderedMap
Definition: custom_map.hpp:148
#define DONE_PORT_NAME
bool IsAddressType(const unsigned int type_index) const
Checks if type_index represents an address type.
HLSFlowStep_Type
Definition: hls_step.hpp:95
This class writes different HDL based descriptions (VHDL, Verilog, SystemC) starting from a structura...
Class specification of the data structures used to manage technology information. ...
void DetectInvalidReturns(const CustomOrderedSet< unsigned int > &reached_body_functions, CustomUnorderedSet< unsigned int > &addr_fun_ids)
Detects return statements resulting in values to be skipped in the discrepancy analysis.
unsigned int GetFunctionReturnType(unsigned int function) const
Return the index associated with the type of the return of the function.
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
const OpGraphInfoConstRef CGetOpGraphInfo() const
Returns the property associated with the graph.
Definition: op_graph.hpp:871
void SelectInitialAddrParam(const CustomOrderedSet< unsigned int > &reached_body_fun_ids, CustomUnorderedMap< unsigned int, TreeNodeSet > &address_parameters)
Selects the initial set of function parameters to skip, iterating on the reached functions with a bod...
std::string present_state_name
The name of the present state signal.
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
const BehavioralHelperConstRef CGetBehavioralHelper() const
Returns the helper associated with the function.
boost::graph_traits< graph >::vertex_iterator VertexIterator
vertex_iterator definition.
Definition: graph.hpp:1307
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
This package is used by all HLS packages to manage resource constraints and characteristics.
bool function_has_to_be_printed(unsigned int f_id) const
returns true if the function body has to be printed by the C backend
Call graph hierarchy.
void SingleStepPropagateParamToSsa(const TreeNodeMap< size_t > &used_ssa, const TreeNodeSet &address_parameters)
Single step used in the loop of PropagateAddrParamToSsa()
static bool is_a_pointer(const tree_managerConstRef &TM, const unsigned int index)
Return if treenode index is a pointer.
Wrapper of design_flow.
#define WRAPPED_PROXY_PREFIX
This package is used to define the storage value scheme adopted by the register allocation algorithms...
#define HIERARCHY_SEPARATOR
This file collects some utility functions.
void CrossPropagateAddrSsa(CustomUnorderedMap< unsigned int, TreeNodeSet > &address_parameters, const CustomOrderedSet< unsigned int > &reached_body_functions, const CustomUnorderedSet< unsigned int > &addr_fun_ids, const CustomUnorderedMap< unsigned int, UnorderedSetStdStable< unsigned int >> &fu_id_to_call_ids, const CustomUnorderedMap< unsigned int, UnorderedSetStdStable< unsigned int >> &call_id_to_called_id)
Propagates the information on the parameters to skip across function calls.
const DiscrepancyRef Discr
void PropagateAddrParamToSsa(const CustomUnorderedMap< unsigned int, TreeNodeSet > &address_parameters, const CustomOrderedSet< unsigned int > &reached_body_fun_ids)
Propagates the information on the ssa to skip to all the ssa in the functions with body...
void SelectAddrSsa(const CustomUnorderedMap< unsigned int, UnorderedSetStdStable< unsigned int >> &fu_id_to_call_ids, const CustomUnorderedMap< unsigned int, UnorderedSetStdStable< unsigned int >> &call_id_to_called_id)
Compute the ssa representing address values.
This class describes all classes used to represent a structural object.
Class specification of the tree_reindex support class.
#define ENTRY_ID
constant used to represent tree node index of entry operation
Definition: op_graph.hpp:79
const tree_managerRef TM
Data structure used to store the functional-unit binding of the vertexes.
const OpGraphConstRef CGetOpGraph(FunctionBehavior::graph_type gt) const
This method returns the operation graphs.
void InProcedurePropagateAddr(const CustomUnorderedMap< unsigned int, TreeNodeSet > &address_parameters, const CustomOrderedSet< unsigned int > &reached_body_functions, CustomUnorderedSet< unsigned int > &addr_fun_ids)
Propagates the information on the ssa to skip to all the ssa in the functions with body...
unsigned int size_t
Definition: test.c:1
static bool is_a_complex(const tree_managerConstRef &TM, const unsigned int index)
Return if treenode index is a complex.
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.
T * get() const
Definition: refcount.hpp:169
DesignFlowStep_Status Exec() override
Executes the step.
this class is used to manage the command-line or XML options.
static unsigned int get_base_index(const tree_managerConstRef &TM, const unsigned int index)
Retrun the base address of a memory access.
static bool is_a_vector(const tree_managerConstRef &TM, const unsigned int index)
Return true if the treenode index is a vector.
Wrapper to call graph.
Control flow graph with feedback.
int debug_level
The debug level.
#define OUTPUT_LEVEL_VERBOSE
verbose debugging print is performed.
refcount< const HLSFlowStepSpecialization > HLSFlowStepSpecializationConstRef
const refcount definition of the class
Definition: hls_step.hpp:93
void InitialPhiResIsAddress(const tree_nodeConstRef &tn)
Determines if the tree_node tn assigns an ssa_name representing an address.
Data structure definition for high-level synthesis flow.
static void ComputeSsaUses(const tree_nodeRef &, TreeNodeMap< size_t > &uses)
recursively compute the references to the ssa_name variables used in a statement
Datastructure to represent memory information in high-level synthesis.
void InitialSsaIsAddress(const tree_nodeConstRef &tn, const CustomUnorderedSet< unsigned int > &addr_fun_ids, const CustomUnorderedMap< unsigned int, UnorderedSetStdStable< unsigned int >> &call_id_to_called_id)
Determines if the tree_node tn assigns an ssa_name representing an address.
Class specification of the manager of the tree structures extracted from the raw file.
const CustomUnorderedSet< std::tuple< HLSFlowStep_Type, HLSFlowStepSpecializationConstRef, HLSFlowStep_Relationship > > ComputeHLSRelationships(const DesignFlowStep::RelationshipType relationship_type) const override
Return the set of analyses in relationship with this design step.
A brief description of the C++ Header File.
static bool is_an_array(const tree_managerConstRef &TM, const unsigned int index)
Return if treenode index is an array or it is equivalent to an array (record recursively having a sin...
void SelectInitialSsa(const CustomOrderedSet< unsigned int > &reached_body_fun_ids, const CustomUnorderedSet< unsigned int > &addr_fun_ids, const CustomUnorderedMap< unsigned int, UnorderedSetStdStable< unsigned int >> &call_id_to_called_id)
Selects the initial set of ssa to skip, iterating on the reached functions with a body and inserting ...
boost::graph_traits< graph >::edge_descriptor EdgeDescriptor
edge definition.
Definition: graph.hpp:1316
#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