PandA-2024.02
FunctionCallOpt.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) 2021-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  */
43 #include "FunctionCallOpt.hpp"
44 
45 #include "Dominance.hpp"
46 #include "Parameter.hpp"
47 #include "application_manager.hpp"
48 #include "basic_block.hpp"
50 #include "call_graph.hpp"
51 #include "call_graph_manager.hpp"
52 #include "dbgPrintHelper.hpp" // for DEBUG_LEVEL_
53 #include "design_flow_graph.hpp"
54 #include "design_flow_manager.hpp"
55 #include "ext_tree_node.hpp"
56 #include "function_behavior.hpp"
57 #include "hls.hpp"
58 #include "hls_manager.hpp"
59 #include "string_manipulation.hpp" // for GET_CLASS
60 #include "tree_basic_block.hpp"
61 #include "tree_helper.hpp"
62 #include "tree_manager.hpp"
63 #include "tree_manipulation.hpp"
64 #include "tree_node.hpp"
65 #include "tree_reindex.hpp"
66 
67 #include <functional>
68 
69 #define PARAMETER_INLINE_MAX_COST "inline-max-cost"
70 #define DEAFULT_MAX_INLINE_CONST 60
71 
76 
77 static const std::set<std::string> inlinedFunctionByDefault{"__mul32", "__umul32", "__mul64", "__umul64"};
78 
80  {call_expr_K, 8}, {mult_expr_K, 3}, {widen_mult_expr_K, 3}, {widen_mult_hi_expr_K, 3},
81  {widen_mult_lo_expr_K, 3}, {trunc_div_expr_K, 3}, {exact_div_expr_K, 3}, {round_div_expr_K, 3},
82  {ceil_div_expr_K, 3}, {floor_div_expr_K, 3}, {trunc_mod_expr_K, 3}, {round_mod_expr_K, 3},
83  {ceil_mod_expr_K, 3}, {floor_mod_expr_K, 3}, {view_convert_expr_K, 0}, {convert_expr_K, 0},
84  {nop_expr_K, 0}, {ssa_name_K, 0}, {addr_expr_K, 0}, {bit_ior_concat_expr_K, 0},
85  {extract_bit_expr_K, 0}};
86 
87 static std::string __arg_suffix(const std::vector<tree_nodeRef>& tns)
88 {
89  std::stringstream suffix;
90  for(const auto& tn : tns)
91  {
93  {
94  suffix << tn;
95  }
96  else
97  {
98  suffix << "_" << STR(GET_INDEX_CONST_NODE(tn));
99  }
100  }
101  const auto hash = std::hash<std::string>{}(suffix.str());
102  suffix.str(std::string());
103  suffix << "_" << std::hex << hash;
104  return suffix.str();
105 }
106 
108  unsigned int _function_id, const DesignFlowManagerConstRef _design_flow_manager)
109  : FunctionFrontendFlowStep(_AppM, _function_id, FUNCTION_CALL_OPT, _design_flow_manager, Param), caller_bb()
110 {
111  debug_level = Param->get_class_debug_level(GET_CLASS(*this), DEBUG_LEVEL_NONE);
112 }
113 
115 
118 {
120  switch(relationship_type)
121  {
123  {
124  relationships.insert(std::make_pair(COMPLETE_BB_GRAPH, SAME_FUNCTION));
125  relationships.insert(std::make_pair(COMPLETE_CALL_GRAPH, WHOLE_APPLICATION));
126  relationships.insert(std::make_pair(FUNCTION_CALL_OPT, CALLED_FUNCTIONS));
127  relationships.insert(std::make_pair(FUNCTION_CALL_TYPE_CLEANUP, SAME_FUNCTION));
128  break;
129  }
131  {
132  break;
133  }
135  {
137  {
138  if(!parameters->getOption<int>(OPT_gcc_openmp_simd))
139  {
140  relationships.insert(std::make_pair(BIT_VALUE, SAME_FUNCTION));
141  }
142  relationships.insert(std::make_pair(COMPLETE_BB_GRAPH, SAME_FUNCTION));
143  relationships.insert(std::make_pair(DETERMINE_MEMORY_ACCESSES, SAME_FUNCTION));
144  }
145  break;
146  }
147  default:
148  {
149  THROW_UNREACHABLE("");
150  }
151  }
152  return relationships;
153 }
154 
156 {
157  for(const auto& id_bb : caller_bb)
158  {
159  if(AppM->CGetFunctionBehavior(id_bb.first)->GetBBVersion() != id_bb.second)
160  {
161  return true;
162  }
163  }
165 }
166 
168 {
169  if(never_inline.empty())
170  {
171  const auto TM = AppM->get_tree_manager();
172  if(parameters->IsParameter(PARAMETER_INLINE_MAX_COST))
173  {
174  inline_max_cost = parameters->GetParameter<size_t>(PARAMETER_INLINE_MAX_COST);
175  }
176  if(parameters->isOption(OPT_inline_functions))
177  {
178  const auto fnames = SplitString(parameters->getOption<std::string>(OPT_inline_functions), ",");
179  for(const auto& fname_cond : fnames)
180  {
181  const auto toks = SplitString(fname_cond, "=");
182  const auto& fname = toks.at(0);
183  const auto fnode = TM->GetFunction(fname);
184  if(fnode)
185  {
186  auto& inline_set = (!(toks.size() > 1) || toks.at(1) == "1") ? always_inline : never_inline;
187  inline_set.insert(fnode->index);
189  "Required " + STR((!(toks.size() > 1) || toks.at(1) == "1") ? "always" : "never") +
190  " inline for function " + fname);
191  }
192  else
193  {
194  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "Required inline function not found: " + fname);
195  }
196  }
197  }
198  for(const auto& defaultInlineFunction : inlinedFunctionByDefault)
199  {
200  const auto fnode = TM->GetFunction(defaultInlineFunction);
201  if(fnode)
202  {
203  always_inline.insert(fnode->index);
204  }
205  }
206  const auto HLSMgr = GetPointer<HLS_manager>(AppM);
207  for(const auto& [symbol, arch] : *HLSMgr->module_arch)
208  {
209  THROW_ASSERT(arch, "Expected initialized architecture for function " + symbol);
210  const auto inline_attr = arch->attrs.find(FunctionArchitecture::func_inline);
211  if(inline_attr != arch->attrs.end())
212  {
213  const auto fnode = TM->GetFunction(symbol);
214  if(fnode)
215  {
216  if(inline_attr->second == "self")
217  {
218  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "Required always inline for function " + symbol);
219  always_inline.insert(GET_INDEX_CONST_NODE(fnode));
220  }
221  else if(inline_attr->second == "off")
222  {
223  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "Required never inline for function " + symbol);
224  never_inline.insert(GET_INDEX_CONST_NODE(fnode));
225  }
226  else if(inline_attr->second == "recursive")
227  {
228  THROW_WARNING("Recursive inline not yet supported.");
229  }
230  }
231  else
232  {
234  "Required inline (" + inline_attr->second + ") function not found: " + symbol);
235  }
236  }
237  }
238  never_inline.insert(0);
239  }
240  caller_bb.clear();
241 }
242 
244 {
245  THROW_ASSERT(!parameters->IsParameter("function-opt") || parameters->GetParameter<bool>("function-opt"),
246  "Function call optimization should not be executed");
247  if(GetPointer<const HLS_manager>(AppM) && GetPointer<const HLS_manager>(AppM)->get_HLS(function_id) &&
248  GetPointer<const HLS_manager>(AppM)->get_HLS(function_id)->Rsch)
249  {
251  "---Function already scheduled, inlining is not possible any more");
253  }
255  const auto TM = AppM->get_tree_manager();
256  const auto fnode = TM->CGetTreeReindex(function_id);
257  const auto fd = GetPointerS<function_decl>(GET_NODE(fnode));
258  THROW_ASSERT(fd->body, "");
259  const auto sl = GetPointerS<statement_list>(GET_NODE(fd->body));
260  bool modified = false;
261  const auto opt_stmts = opt_call.find(function_id);
262  if(opt_stmts != opt_call.end())
263  {
264  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Performing call optimization:");
267  for(const auto& stmt_opt : opt_stmts->second)
268  {
269  const auto& stmt_id = std::get<0>(stmt_opt);
270  const auto& opt_type = std::get<1>(stmt_opt);
271  const auto stmt = TM->CGetTreeReindex(stmt_id);
272  if(stmt)
273  {
274  const auto gn = GetPointerS<const gimple_node>(GET_CONST_NODE(stmt));
275  const auto bb_it = sl->list_of_bloc.find(gn->bb_index);
276  if(gn->bb_index != 0 && bb_it != sl->list_of_bloc.end())
277  {
278  const auto& bb = bb_it->second;
279  if(std::find_if(bb->CGetStmtList().cbegin(), bb->CGetStmtList().cend(), [&](const tree_nodeRef& tn) {
280  return GET_INDEX_CONST_NODE(tn) == stmt_id;
281  }) != bb->CGetStmtList().cend())
282  {
283  if(!AppM->ApplyNewTransformation())
284  {
286  "---Max transformations reached, skipping function inlining...");
287  break;
288  }
289  if(opt_type == FunctionOptType::INLINE)
290  {
292  "Inlining required for call statement " + GET_CONST_NODE(stmt)->ToString());
293  tree_man->InlineFunctionCall(stmt, fnode);
294  AppM->RegisterTransformation(GetName(), nullptr);
295  modified = true;
296  }
297  else if(opt_type == FunctionOptType::VERSION)
298  {
300  "Versioning required for call statement " + GET_CONST_NODE(stmt)->ToString());
301  const auto version_suffix = [&]() -> std::string {
302  const auto call_stmt = GET_CONST_NODE(stmt);
303  if(call_stmt->get_kind() == gimple_call_K)
304  {
305  const auto gc = GetPointerS<const gimple_call>(call_stmt);
306  return __arg_suffix(gc->args);
307  }
308  else if(call_stmt->get_kind() == gimple_assign_K)
309  {
310  const auto ga = GetPointerS<const gimple_assign>(call_stmt);
311  const auto ce = GetPointer<const call_expr>(GET_CONST_NODE(ga->op1));
312  return __arg_suffix(ce->args);
313  }
314  THROW_UNREACHABLE("Unsupported call statement: " + call_stmt->get_kind_text() + " " +
315  STR(stmt));
316 
317  return "";
318  }();
319  const auto _modified = tree_man->VersionFunctionCall(stmt, fnode, version_suffix);
320  if(_modified)
321  {
322  AppM->RegisterTransformation(GetName(), stmt);
323  modified = true;
324  }
325  }
326  else
327  {
328  THROW_UNREACHABLE("Unknown function call optimization type: " + STR(opt_type));
329  }
330  }
331  else
332  {
334  "Statement " + STR(stmt_id) + " was not present in BB" + STR(bb->number));
335  }
336  }
337  else
338  {
340  "BB" + STR(gn->bb_index) + " was not found in current function");
341  }
342  }
343  else
344  {
346  "Statement " + STR(stmt_id) + " was not in tree manager");
347  }
348  }
350  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Performed call inlining");
351  opt_call.erase(function_id);
352  }
353 
354  if(parameters->isOption(OPT_top_design_name) &&
355  TM->GetFunction(parameters->getOption<std::string>(OPT_top_design_name))->index == function_id)
356  {
358  "Current function is marked as top RTL design, skipping...");
359  }
360  else if(never_inline.count(function_id))
361  {
362  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Current function is marked as never inline, skipping...");
363  }
364  else
365  {
366  const auto CGM = AppM->CGetCallGraphManager();
367  const auto CG = CGM->CGetCallGraph();
368  const auto function_v = CGM->GetVertex(function_id);
369  const auto call_count = [&]() -> size_t {
370  size_t call_points = 0u;
371  BOOST_FOREACH(EdgeDescriptor ie, boost::in_edges(function_v, *CG))
372  {
373  const auto caller_info = CG->CGetFunctionEdgeInfo(ie);
374  call_points += static_cast<size_t>(caller_info->direct_call_points.size());
375  call_points += static_cast<size_t>(caller_info->indirect_call_points.size());
376  call_points += static_cast<size_t>(caller_info->function_addresses.size());
377  }
378  return call_points;
379  }();
380  if(call_count != 0)
381  {
382  const auto loop_count = detect_loops(sl);
383  bool has_simd = false;
384  const auto body_cost = compute_cost(sl, has_simd);
385  const auto omp_simd_enabled = parameters->getOption<int>(OPT_gcc_openmp_simd);
386  has_simd &= omp_simd_enabled;
387  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Current function information:");
388  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Internal loops : " + STR(loop_count));
389  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Call points : " + STR(call_count));
390  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Body cost : " + STR(body_cost));
391  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---OpenMP SIMD : " + STR(has_simd ? "yes" : "no"));
393  "---Force inline : " + STR(always_inline.count(function_id) ? "yes" : "no"));
394  const bool inline_funciton = always_inline.count(function_id) || ((body_cost * call_count) <= inline_max_cost);
395  if(has_simd)
396  {
398  "Current function has OpenMP SIMD constructs, inlining postponed");
399  }
400  else
401  {
402  BOOST_FOREACH(EdgeDescriptor ie, boost::in_edges(function_v, *CG))
403  {
404  const auto caller_id = CGM->get_function(ie.m_source);
405  caller_bb.insert(std::make_pair(caller_id, AppM->CGetFunctionBehavior(caller_id)->GetBBVersion()));
407  "Analysing call points from " +
409  GetPointerS<const function_decl>(TM->CGetTreeNode(caller_id))));
411  const auto caller_node = TM->CGetTreeNode(caller_id);
412  THROW_ASSERT(caller_node->get_kind() == function_decl_K, "");
413  const auto caller_fd = GetPointerS<const function_decl>(caller_node);
414  THROW_ASSERT(caller_fd->body, "");
415  const auto caller_sl = GetPointerS<const statement_list>(GET_CONST_NODE(caller_fd->body));
416  if(omp_simd_enabled)
417  {
418  const auto caller_has_simd = tree_helper::has_omp_simd(caller_sl);
419  if(caller_has_simd)
420  {
422  "<--Caller has OpenMP SIMD constructs, analysis postponed");
423  continue;
424  }
425  }
426  const auto caller_info = CG->CGetFunctionEdgeInfo(ie);
427  bool all_inlined = true;
428  for(const auto& call_id : caller_info->direct_call_points)
429  {
430  const auto call_stmt = TM->CGetTreeNode(call_id);
432  "Analysing direct call point " + STR(call_stmt));
433  const auto call_gn = GetPointerS<const gimple_node>(call_stmt);
434  if(call_gn->vdef || call_gn->vuses.size() || call_gn->vovers.size())
435  {
436  // TODO: alias analysis is not able to handle inlining yet
437  all_inlined = false;
439  "---Call statement carries alias dependencies, skipping...");
440  continue;
441  }
442  if(inline_funciton)
443  {
444  if(!omp_simd_enabled || loop_count == 0)
445  {
446  const auto is_unique_bb_call = [&]() -> bool {
447  THROW_ASSERT(caller_sl->list_of_bloc.count(call_gn->bb_index),
448  "BB" + STR(call_gn->bb_index) + " not found in function " +
449  tree_helper::GetMangledFunctionName(caller_fd) + " (" + STR(call_id) + ")");
450  const auto bb = caller_sl->list_of_bloc.at(call_gn->bb_index);
451  for(const auto& tn : bb->CGetStmtList())
452  {
453  if(tn->index != call_gn->index &&
454  (GET_CONST_NODE(tn)->get_kind() == gimple_call_K ||
455  (GET_CONST_NODE(tn)->get_kind() == gimple_assign_K &&
456  GET_CONST_NODE(GetPointerS<const gimple_assign>(GET_CONST_NODE(tn))->op1)
457  ->get_kind() == call_expr_K)))
458  {
459  return false;
460  }
461  }
462  return true;
463  }();
464  if(is_unique_bb_call || loop_count == 0)
465  {
466  opt_call[caller_id].insert(std::make_pair(call_id, FunctionOptType::INLINE));
468  "---" +
469  STR(always_inline.count(function_id) ? "Always inline function" :
470  "Low body cost function") +
471  ", inlining required");
472  continue;
473  }
474  else
475  {
477  "---BB" + STR(call_gn->bb_index) + " from function " +
479  " has multiple call points, skipping...");
480  }
481  }
482  else
483  {
486  "---Inlining of functions with internal loops disabled with OpenMP, skipping...");
487  }
488  }
489  const auto all_const_args = HasConstantArgs(TM->CGetTreeReindex(call_id));
490  if(all_const_args && loop_count == 0)
491  {
492  opt_call[caller_id].insert(std::make_pair(call_id, FunctionOptType::VERSION));
494  "---Current call has all constant arguments, versioning required");
495  continue;
496  }
497  all_inlined = false;
498  }
499  if(all_inlined)
500  {
501  caller_bb.erase(caller_id);
502  }
505  "Analysed call points from " +
507  GetPointerS<const function_decl>(TM->CGetTreeNode(caller_id))));
508  }
509  }
510  }
511  else
512  {
514  "Current function has zero call points, skipping analysis...");
515  }
516  }
518  if(modified)
519  {
520  function_behavior->UpdateBBVersion();
521  function_behavior->UpdateBitValueVersion();
523  }
525 }
526 
527 void FunctionCallOpt::RequestCallOpt(const tree_nodeConstRef& call_stmt, unsigned int caller_id, FunctionOptType opt)
528 {
529 #if HAVE_ASSERTS
530  const auto stmt_kind = GET_CONST_NODE(call_stmt)->get_kind();
531  bool is_call = stmt_kind == gimple_call_K;
532  if(stmt_kind == gimple_assign_K)
533  {
534  const auto rhs = GetPointerS<const gimple_assign>(GET_CONST_NODE(call_stmt))->op1;
535  const auto rhs_kind = GET_CONST_NODE(rhs)->get_kind();
536  is_call |= rhs_kind == call_expr_K || rhs_kind == aggr_init_expr_K;
537  }
538 #endif
539  THROW_ASSERT(is_call, "Statement does not contain a call");
540  opt_call[caller_id].insert(std::make_pair(GET_INDEX_CONST_NODE(call_stmt), opt));
541 }
542 
544 {
545  const auto all_constant = [](const std::vector<tree_nodeRef>& tns) {
546  for(const auto& tn : tns)
547  {
548  if(!tree_helper::IsConstant(tn))
549  {
550  return false;
551  }
552  }
553  return true;
554  };
555  const auto call_kind = GET_CONST_NODE(call_stmt)->get_kind();
556  if(call_kind == gimple_call_K)
557  {
558  const auto gc = GetPointerS<const gimple_call>(GET_CONST_NODE(call_stmt));
559  return all_constant(gc->args);
560  }
561  else if(call_kind == gimple_assign_K)
562  {
563  const auto ga = GetPointerS<const gimple_assign>(GET_CONST_NODE(call_stmt));
564  THROW_ASSERT(GET_CONST_NODE(ga->op1)->get_kind() == call_expr_K, "");
565  const auto ce = GetPointerS<const call_expr>(GET_CONST_NODE(ga->op1));
566  return all_constant(ce->args);
567  }
568  THROW_UNREACHABLE("Expected call statement: " + tree_node::GetString(call_kind) + " - " + STR(call_stmt));
569  return false;
570 }
571 
572 size_t FunctionCallOpt::compute_cost(const statement_list* body, bool& has_simd)
573 {
574  size_t total_cost = 0;
575  has_simd = false;
576  for(const auto& bb : body->list_of_bloc)
577  {
578  for(const auto& stmt_rdx : bb.second->CGetStmtList())
579  {
580  const auto stmt = GET_CONST_NODE(stmt_rdx);
581  if(stmt->get_kind() == gimple_assign_K)
582  {
583  const auto ga = GetPointerS<const gimple_assign>(stmt);
584  const auto op_kind = GET_CONST_NODE(ga->op1)->get_kind();
585  const auto op_cost = op_costs.find(op_kind);
586  if(op_cost != op_costs.end())
587  {
588  total_cost += op_cost->second;
589  }
590  else
591  {
592  if(op_kind == lshift_expr_K || op_kind == rshift_expr_K || op_kind == bit_and_expr_K ||
593  op_kind == bit_ior_expr_K)
594  {
595  total_cost += !tree_helper::IsConstant(GetPointerS<const binary_expr>(GET_CONST_NODE(ga->op1))->op1);
596  }
597  else
598  {
599  total_cost += 1;
600  }
601  }
602  }
603  else if(stmt->get_kind() == gimple_cond_K || stmt->get_kind() == gimple_call_K)
604  {
605  total_cost += 8;
606  }
607  else if(stmt->get_kind() == gimple_multi_way_if_K)
608  {
609  const auto mw = GetPointerS<const gimple_multi_way_if>(stmt);
610  total_cost += mw->list_of_cond.size() * 8ULL;
611  }
612  else if(stmt->get_kind() == gimple_asm_K)
613  {
614  const auto ga = GetPointerS<const gimple_asm>(stmt);
615  total_cost += ga->str.size() / 5;
616  }
617  else if(stmt->get_kind() == gimple_pragma_K)
618  {
619  const auto gp = GetPointerS<const gimple_pragma>(stmt);
620  if(gp->scope && GetPointer<const omp_pragma>(GET_CONST_NODE(gp->scope)))
621  {
622  const auto sp = GetPointer<const omp_simd_pragma>(GET_CONST_NODE(gp->directive));
623  if(sp)
624  {
625  has_simd = true;
626  }
627  }
628  }
629  }
630  }
631  return total_cost;
632 }
633 
635 {
637  BBGraphsCollectionRef bb_graphs_collection(
639  BBGraph cfg(bb_graphs_collection, CFG_SELECTOR);
640  CustomUnorderedMap<unsigned int, vertex> inverse_vertex_map;
642  for(const auto& block : body->list_of_bloc)
643  {
644  inverse_vertex_map.insert(
645  std::make_pair(block.first, bb_graphs_collection->AddVertex(BBNodeInfoRef(new BBNodeInfo(block.second)))));
646  }
647 
649  for(const auto& curr_bb_pair : body->list_of_bloc)
650  {
651  const auto& curr_bbi = curr_bb_pair.first;
652  const auto& curr_bb = curr_bb_pair.second;
653  for(const auto& lop : curr_bb->list_of_pred)
654  {
655  THROW_ASSERT(static_cast<bool>(inverse_vertex_map.count(lop)),
656  "BB" + STR(lop) + " (successor of BB" + STR(curr_bbi) + ") does not exist");
657  bb_graphs_collection->AddEdge(inverse_vertex_map.at(lop), inverse_vertex_map.at(curr_bbi), CFG_SELECTOR);
658  }
659 
660  for(const auto& los : curr_bb->list_of_succ)
661  {
662  if(los == bloc::EXIT_BLOCK_ID)
663  {
664  bb_graphs_collection->AddEdge(inverse_vertex_map.at(curr_bbi), inverse_vertex_map.at(los), CFG_SELECTOR);
665  }
666  }
667 
668  if(curr_bb->list_of_succ.empty())
669  {
670  bb_graphs_collection->AddEdge(inverse_vertex_map.at(curr_bbi), inverse_vertex_map.at(bloc::EXIT_BLOCK_ID),
671  CFG_SELECTOR);
672  }
673  }
674  bb_graphs_collection->AddEdge(inverse_vertex_map.at(bloc::ENTRY_BLOCK_ID),
675  inverse_vertex_map.at(bloc::EXIT_BLOCK_ID), CFG_SELECTOR);
676  std::map<size_t, UnorderedSetStdStable<vertex>> sccs;
678  size_t loop_count = 0;
679  for(const auto& scc : sccs)
680  {
681  if(scc.second.size() > 1)
682  {
683  loop_count++;
684  continue;
685  }
686  THROW_ASSERT(scc.second.size() == 1, "");
687  const auto bb_v = *scc.second.begin();
688  const auto& bb = cfg.CGetBBNodeInfo(bb_v)->block;
689  if(std::find(bb->list_of_succ.begin(), bb->list_of_succ.end(), bb->number) != bb->list_of_succ.end())
690  {
691  loop_count++;
692  }
693  }
694  return loop_count;
695 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
Data structure representing the entire HLS information.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
static const std::set< std::string > inlinedFunctionByDefault
File containing functions and utilities to support the printing of debug messagges.
Step successfully executed.
static bool IsConstant(const tree_nodeConstRef &node)
Return if a tree node is a constant object.
Definition of the node_info object for the basic_block graph.
#define GET_CLASS(obj)
Macro returning the actual type of an object.
This struct specifies the statement_list node.
Definition: tree_node.hpp:4662
#define PARAMETER_INLINE_MAX_COST
Definition of the class representing a generic C application.
const int output_level
The output level.
const std::vector< std::string > SplitString(const std::string &input, const std::string &separators)
Function which splits a string into tokens.
std::string GetName() const override
Return the name of this design step.
void GetStronglyConnectedComponents(std::map< size_t, UnorderedSetStdStable< boost::graph_traits< graphs_collection >::vertex_descriptor >> &strongly_connected_components) const
Compute the strongly connected components of the graph.
Definition: graph.hpp:957
RelationshipType
The relationship type.
Source must be executed to satisfy target.
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
static CustomSet< unsigned int > never_inline
Set of never inlined functions.
static std::string GetString(const enum kind k)
Given a kind, return the corresponding string.
Definition: tree_node.cpp:120
unsigned int InlineFunctionCall(const tree_nodeRef &call_node, const tree_nodeRef &caller_node)
Execute function call inlining of given call statement (call graph must be recomputed after inlining)...
CustomOrderedMap< T, U > CustomMap
Definition: custom_map.hpp:167
std::map< unsigned int, blocRef > list_of_bloc
list_of_bloc field is the list of basic block. If this field is null then the list_of_stmt field is n...
Definition: tree_node.hpp:4673
static const unsigned int EXIT_BLOCK_ID
constant identifying the exit basic block
This class provides methods to build a basic blocks graph.
Data structure describing a basic block at tree level.
#define OUTPUT_LEVEL_MINIMUM
minimum debugging print is performed.
static std::string GetMangledFunctionName(const function_decl *fd)
Return the mangled function name.
#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.
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
std::string ToString(ActorGraphBackend_Type actor_graph_backend_type)
Header include.
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
CustomMap< unsigned int, unsigned int > caller_bb
static void RequestCallOpt(const tree_nodeConstRef &call_stmt, unsigned int caller_id, FunctionOptType opt)
Request optimization for given call statement.
Class used to describe a particular graph with basic blocks as nodes.
DesignFlowStep_Status InternalExec() override
Computes the operations CFG graph data structure.
const CustomUnorderedSet< std::pair< FrontendFlowStepType, FunctionRelationship > > ComputeFrontendRelationships(const DesignFlowStep::RelationshipType relationship_type) const override
Return the set of analyses in relationship with this design step.
absl::flat_hash_map< T, U, Hash, Eq, Alloc > CustomUnorderedMap
Definition: custom_map.hpp:148
static CustomSet< unsigned int > always_inline
Set of always inlined functions.
FunctionOptType
Information associated with the whole basic-block graph.
static std::string __arg_suffix(const std::vector< tree_nodeRef > &tns)
Classes to describe design flow graph.
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
DesignFlowStep_Status GetStatus() const
Return the status of this design step.
Classes specification of the tree_node data structures.
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
Call graph hierarchy.
Class defining some useful functions to create tree nodes and to manipulate the tree manager...
#define DEBUG_LEVEL_NONE
no debugging print is performed.
static bool has_omp_simd(const statement_list *sl)
Check if omp simd pragmas are present in given statement list.
Wrapper of design_flow.
This struct specifies the block node.
Definition: tree_node.hpp:1820
This file collects some utility functions.
const unsigned int function_id
The index of the function to be analyzed.
size_t compute_cost(const statement_list *body, bool &has_simd)
Compute function body cost based on statements&#39; types.
const application_managerRef AppM
The application manager.
bool VersionFunctionCall(const tree_nodeRef &call_node, const tree_nodeRef &caller_node, const std::string &version_suffix)
Perform function call versioning.
Class specification of the tree_reindex support class.
static const unsigned int ENTRY_BLOCK_ID
constant identifying the entry basic block
Class specification of the basic_block structure.
const BBNodeInfoConstRef CGetBBNodeInfo(const vertex node) const
Return the info associated with a basic block.
static bool HasConstantArgs(const tree_nodeConstRef &call_stmt)
Check if given call statement performs a call with all constant arguments.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
Classes specification of the tree_node data structures not present in the gcc.
this class is used to manage the command-line or XML options.
FunctionCallOpt(const ParameterConstRef Param, const application_managerRef AppM, unsigned int function_id, const DesignFlowManagerConstRef design_flow_manager)
Constructor.
Wrapper to call graph.
#define DEAFULT_MAX_INLINE_CONST
void Initialize() override
Initialize the step (i.e., like a constructor, but executed just before exec.
static size_t inline_max_cost
int debug_level
The debug level.
static CustomMap< unsigned int, CustomSet< std::tuple< unsigned int, FunctionOptType > > > opt_call
#define GET_INDEX_CONST_NODE(t)
Definition: tree_node.hpp:363
#define CFG_SELECTOR
Control flow graph edge selector.
Data structure definition for high-level synthesis flow.
refcount< BBGraphInfo > BBGraphInfoRef
refcount definition of the class
static CustomUnorderedMap< kind, size_t > op_costs
This class creates a layer to add nodes and to manipulate the tree_nodes manager. ...
Class specification of the manager of the tree structures extracted from the raw file.
A brief description of the C++ Header File.
~FunctionCallOpt() override
Destructor.
const FunctionBehaviorRef function_behavior
The function behavior of the function to be analyzed.
int sl
Definition: adpcm.c:105
size_t detect_loops(const statement_list *body) const
Check if given function body has loops.
This structure defines graphs where nodes are basic_blocks.
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:52 for PandA-2024.02 by doxygen 1.8.13