PandA-2024.02
call_graph_manager.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  */
45 #include "call_graph_manager.hpp"
46 
47 #include "Parameter.hpp"
48 #include "application_manager.hpp"
49 #include "behavioral_helper.hpp"
50 #include "call_graph.hpp"
51 #include "dbgPrintHelper.hpp"
52 #include "exceptions.hpp"
53 #include "ext_tree_node.hpp"
54 #include "function_behavior.hpp"
55 #include "graph.hpp"
56 #include "loops.hpp"
57 #include "op_graph.hpp"
58 #include "string_manipulation.hpp"
59 #include "tree_basic_block.hpp"
60 #include "tree_helper.hpp"
61 #include "tree_manager.hpp"
62 #include "tree_node.hpp"
63 #include "tree_reindex.hpp"
64 
65 #include <boost/tuple/tuple.hpp>
66 
67 #include <algorithm>
68 #include <iterator>
69 #include <list>
70 #include <string>
71 #include <utility>
72 #include <vector>
73 
74 #include "config_HAVE_ASSERTS.hpp"
75 
82 #define ADD_CALL_POINT(g, e, newstmt) get_edge_info<function_graph_edge_info>(e, *(g))->call_points.insert(newstmt)
83 
87 struct CalledFunctionsVisitor : public boost::default_dfs_visitor
88 {
89  private:
92 
95 
98 
101 
102  public:
110  CalledFunctionsVisitor(const bool _allow_recursive_functions, const CallGraphManager* _call_graph_manager,
111  CustomSet<unsigned int>& _body_functions, CustomSet<unsigned int>& _library_functions)
112  : allow_recursive_functions(_allow_recursive_functions),
113  call_graph_manager(_call_graph_manager),
114  body_functions(_body_functions),
115  library_functions(_library_functions)
116  {
117  }
118 
119  void back_edge(const EdgeDescriptor& e, const CallGraph& g)
120  {
121  if(!allow_recursive_functions)
122  {
123  const auto& behaviors = g.CGetCallGraphInfo()->behaviors;
124  const auto source = boost::source(e, g);
125  const auto target = boost::target(e, g);
126  THROW_ERROR(
127  "Recursive functions not yet supported: " +
128  behaviors.at(call_graph_manager->get_function(source))->CGetBehavioralHelper()->get_function_name() +
129  "-->" +
130  behaviors.at(call_graph_manager->get_function(target))->CGetBehavioralHelper()->get_function_name());
131  }
132  }
133 
139  void finish_vertex(const vertex& u, const CallGraph& g)
140  {
141  const auto f_id = Cget_node_info<FunctionInfo, graph>(u, g)->nodeID;
142  if(g.CGetCallGraphInfo()->behaviors.at(f_id)->CGetBehavioralHelper()->has_implementation())
143  {
144  body_functions.insert(f_id);
145  }
146  else
147  {
148  library_functions.insert(f_id);
149  }
150  }
151 };
152 
153 CallGraphManager::CallGraphManager(const FunctionExpanderConstRef _function_expander,
154  const bool _allow_recursive_functions, const tree_managerConstRef _tree_manager,
155  const ParameterConstRef _Param)
156  : call_graphs_collection(new CallGraphsCollection(CallGraphInfoRef(new CallGraphInfo()), _Param)),
157  call_graph(new CallGraph(call_graphs_collection, STD_SELECTOR | FEEDBACK_SELECTOR)),
158  tree_manager(_tree_manager),
159  allow_recursive_functions(_allow_recursive_functions),
160  Param(_Param),
161  debug_level(_Param->get_class_debug_level(GET_CLASS(*this))),
162  function_expander(_function_expander)
163 {
164 }
165 
167 
168 void CallGraphManager::AddFunction(unsigned int new_function_id, const FunctionBehaviorRef fun_behavior)
169 {
171  "---Adding function: " + fun_behavior->CGetBehavioralHelper()->get_function_name() +
172  " id: " + STR(new_function_id));
173  if(!IsVertex(new_function_id))
174  {
176  vertex v = call_graphs_collection->AddVertex(NodeInfoRef(new FunctionInfo()));
177  GET_NODE_INFO(call_graphs_collection.get(), FunctionInfo, v)->nodeID = new_function_id;
178  functionID_vertex_map[new_function_id] = v;
179  called_by[new_function_id] = CustomOrderedSet<unsigned int>();
180  call_graph->GetCallGraphInfo()->behaviors[new_function_id] = fun_behavior;
182  }
183  else
184  {
185  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---vertex already present");
186  THROW_ASSERT(call_graph->GetCallGraphInfo()->behaviors.at(new_function_id) == fun_behavior,
187  "adding a different behavior for " + STR(new_function_id) +
188  " prev: " + STR(call_graph->GetCallGraphInfo()->behaviors.at(new_function_id)) +
189  " new: " + STR(fun_behavior));
190  }
191 }
192 
193 void CallGraphManager::AddCallPoint(unsigned int caller_id, unsigned int called_id, unsigned int call_id,
194  enum FunctionEdgeInfo::CallType call_type)
195 {
196 #if !defined(NDEBUG) || HAVE_ASSERTS
197  const auto caller_name = "(" + STR(caller_id) + ") " +
199  tree_manager, GetPointerS<const function_decl>(tree_manager->CGetTreeNode(caller_id)));
200  const auto called_name = "(" + STR(called_id) + ") " +
202  tree_manager, GetPointerS<const function_decl>(tree_manager->CGetTreeNode(called_id)));
203 #endif
205  "---Adding call with id: " + STR(call_id) + " from " + caller_name + " to " + called_name);
206  if(IsCallPoint(caller_id, called_id, call_id, call_type))
207  {
208  return;
209  }
210  THROW_ASSERT(!IsCallPoint(caller_id, called_id, call_id, FunctionEdgeInfo::CallType::call_any),
211  "call id " + STR(call_id) + " from " + caller_name + " to " + called_name +
212  " was already in the call graph with the same call type");
213  THROW_ASSERT(IsVertex(caller_id), "caller function should be already added to the call_graph");
214  THROW_ASSERT(IsVertex(called_id), "called function should be already added to the call_graph");
215  const auto src = GetVertex(caller_id);
216  const auto tgt = GetVertex(called_id);
217  if(called_by.at(caller_id).find(called_id) == called_by.at(caller_id).end())
218  {
220  "---No previous call from " + caller_name + " to " + called_name);
221  called_by.at(caller_id).insert(called_id);
222  call_graphs_collection->AddEdge(src, tgt, STD_SELECTOR);
223  try
224  {
225  std::list<vertex> topological_sort;
227  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Sorted call graph");
228  }
229  catch(std::exception& e)
230  {
231  call_graphs_collection->RemoveSelector(src, tgt, STD_SELECTOR);
232  call_graphs_collection->AddSelector(src, tgt, FEEDBACK_SELECTOR);
233  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Something wrong in call insertion");
234  }
235  }
236 
237  EdgeDescriptor e;
238  bool found;
239  boost::tie(e, found) = boost::edge(src, tgt, *CGetCallGraph());
240  THROW_ASSERT(found, "call id " + STR(call_id) + " from " + caller_name + " to " + called_name +
241  " was not in the call graph");
242 
243  const auto functionEdgeInfo = get_edge_info<FunctionEdgeInfo, CallGraph>(e, *call_graph);
244  THROW_ASSERT(call_id, "");
245 
246  switch(call_type)
247  {
249  functionEdgeInfo->direct_call_points.insert(call_id);
251  break;
253  functionEdgeInfo->indirect_call_points.insert(call_id);
254  addressed_functions.insert(called_id);
255  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "added indirect call");
256  break;
258  functionEdgeInfo->function_addresses.insert(call_id);
259  addressed_functions.insert(called_id);
260  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "added taken address");
261  break;
263  default:
264  THROW_UNREACHABLE("unexpected call type");
265  }
267 }
268 
269 bool CallGraphManager::IsCallPoint(unsigned int caller_id, unsigned int called_id, unsigned int call_id,
270  enum FunctionEdgeInfo::CallType call_type) const
271 {
272  if(!IsVertex(caller_id) || !IsVertex(called_id))
273  {
275  return false;
276  }
277 
278  if(called_by.at(caller_id).find(called_id) == called_by.at(caller_id).end())
279  {
281  return false;
282  }
283 
285  const auto src = GetVertex(caller_id);
286  const auto tgt = GetVertex(called_id);
287 
288  EdgeDescriptor e;
289  bool found;
290  boost::tie(e, found) = boost::edge(src, tgt, *CGetCallGraph());
291 #if HAVE_ASSERTS
292  const auto caller_name = "(" + STR(caller_id) + ") " +
294  tree_manager, GetPointerS<const function_decl>(tree_manager->CGetTreeNode(caller_id)));
295  const auto called_name = "(" + STR(called_id) + ") " +
297  tree_manager, GetPointerS<const function_decl>(tree_manager->CGetTreeNode(called_id)));
298 #endif
299  THROW_ASSERT(found, "call id " + STR(call_id) + " from " + caller_name + " to " + called_name +
300  " was not in the call graph");
301 
302  const auto functionEdgeInfo = get_edge_info<FunctionEdgeInfo, CallGraph>(e, *call_graph);
303 
304  bool res = false;
305  switch(call_type)
306  {
308  res = functionEdgeInfo->direct_call_points.count(call_id);
309  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "direct call! present? " + STR(res));
310  break;
312  res = functionEdgeInfo->indirect_call_points.count(call_id);
313  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "indirect call! present? " + STR(res));
314  break;
316  res = functionEdgeInfo->function_addresses.count(call_id);
317  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "function_address! present? " + STR(res));
318  break;
320  res = functionEdgeInfo->direct_call_points.count(call_id) ||
321  functionEdgeInfo->indirect_call_points.count(call_id) ||
322  functionEdgeInfo->function_addresses.count(call_id);
323  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "any call! present? " + STR(res));
324  break;
325  default:
326  THROW_UNREACHABLE("unexpected call type");
327  }
328  return res;
329 }
330 
331 void CallGraphManager::AddFunctionAndCallPoint(unsigned int caller_id, unsigned int called_id, unsigned int call_id,
332  const FunctionBehaviorRef called_function_behavior,
333  enum FunctionEdgeInfo::CallType call_type)
334 {
335  AddFunction(called_id, called_function_behavior);
336  AddCallPoint(caller_id, called_id, call_id, call_type);
337 }
338 
340  unsigned int called_id, unsigned int call_id,
341  enum FunctionEdgeInfo::CallType call_type)
342 {
344  tree_manager, GetPointer<const function_decl>(tree_manager->CGetTreeNode(called_id))) != BUILTIN_WAIT_CALL)
345  {
346  if(!IsVertex(called_id))
347  {
348  bool has_body = tree_manager->get_implementation_node(called_id) != 0;
349  BehavioralHelperRef helper =
350  BehavioralHelperRef(new BehavioralHelper(AppM, called_id, has_body, AppM->get_parameter()));
351  FunctionBehaviorRef FB = FunctionBehaviorRef(new FunctionBehavior(AppM, helper, AppM->get_parameter()));
352  AddFunctionAndCallPoint(caller_id, called_id, call_id, FB, call_type);
353  }
354  else
355  {
356  AddCallPoint(caller_id, called_id, call_id, call_type);
357  }
358  }
359 }
360 
361 void CallGraphManager::RemoveCallPoint(EdgeDescriptor e, const unsigned int callid)
362 {
363  const auto called_id = Cget_node_info<FunctionInfo, CallGraph>(boost::target(e, *call_graph), *call_graph)->nodeID;
364  const auto called_name = tree_helper::print_function_name(
365  tree_manager, GetPointerS<const function_decl>(tree_manager->CGetTreeNode(called_id)));
366  if(called_name == BUILTIN_WAIT_CALL)
367  {
368  return;
369  }
370  const auto caller_id = Cget_node_info<FunctionInfo, CallGraph>(boost::source(e, *call_graph), *call_graph)->nodeID;
371 
372  const auto edge_info = get_edge_info<FunctionEdgeInfo, CallGraph>(e, *call_graph);
373  auto& direct_calls = edge_info->direct_call_points;
374  auto& indirect_calls = edge_info->indirect_call_points;
375  auto& function_addresses = edge_info->function_addresses;
376 
377 #if HAVE_ASSERTS
378  int found_calls = 0;
379 #endif
380  const auto dir_it = direct_calls.find(callid);
381  if(dir_it != direct_calls.end())
382  {
383  direct_calls.erase(callid);
384 #if HAVE_ASSERTS
385  found_calls++;
386 #endif
387  }
388  const auto indir_it = indirect_calls.find(callid);
389  if(indir_it != indirect_calls.end())
390  {
391  indirect_calls.erase(callid);
392 #if HAVE_ASSERTS
393  found_calls++;
394 #endif
395  }
396  const auto addr_it = function_addresses.find(callid);
397  if(addr_it != function_addresses.end())
398  {
399  function_addresses.erase(callid);
400 #if HAVE_ASSERTS
401  found_calls++;
402 #endif
403  }
404 
405 #if !defined(NDEBUG) || HAVE_ASSERTS
406  const auto caller_name = "(" + STR(caller_id) + ") " +
408  tree_manager, GetPointerS<const function_decl>(tree_manager->CGetTreeNode(caller_id)));
409 #endif
410  THROW_ASSERT(found_calls, "call id " + STR(callid) + " is not a call point in function " + caller_name +
411  " for function (" + STR(called_id) + ") " + called_name);
412  THROW_ASSERT(found_calls == 1, "call id " + STR(callid) + " is a multiple call point in function " + caller_name +
413  " for function (" + STR(called_id) + ") " + called_name);
414 
415  if(direct_calls.empty() && indirect_calls.empty() && function_addresses.empty())
416  {
418  "Removed function call edge: " + caller_name + " -> (" + STR(called_id) + ") " + called_name);
419  const auto called_v = boost::target(e, *call_graphs_collection);
420  boost::remove_edge(boost::source(e, *call_graphs_collection), called_v, *call_graphs_collection);
421  called_by.at(caller_id).erase(called_id);
422  call_graphs_collection->RemoveSelector(e);
424  // InEdgeIterator it, it_end;
425  // boost::tie(it, it_end) = boost::in_edges(called_v, *call_graph);
426  // if(it == it_end)
427  // {
428  // call_graphs_collection->RemoveVertex(called_v);
429  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Removed dangling function vertex: (" +
430  // STR(called_id) + ") " + called_name);
431  // }
432  }
433  else
434  {
436  "There are still " + STR(direct_calls.size()) + " direct calls, " + STR(indirect_calls.size()) +
437  " indirect calls, and " + STR(function_addresses.size()) +
438  " places where the address is taken");
439  }
440  if(indirect_calls.empty() && function_addresses.empty())
441  {
442  addressed_functions.erase(called_id);
443  }
444 }
445 
446 void CallGraphManager::RemoveCallPoint(const unsigned int caller_id, const unsigned int called_id,
447  const unsigned int call_id)
448 {
449  const auto called_name = tree_helper::print_function_name(
450  tree_manager, GetPointer<const function_decl>(tree_manager->CGetTreeNode(called_id)));
451  if(called_name == BUILTIN_WAIT_CALL)
452  {
453  return;
454  }
455  const auto caller_vertex = GetVertex(caller_id);
456  const auto called_vertex = GetVertex(called_id);
457  EdgeDescriptor e;
458  bool found;
459  boost::tie(e, found) = boost::edge(caller_vertex, called_vertex, *CGetCallGraph());
460 #if HAVE_ASSERTS
461  const auto caller_name = "(" + STR(caller_id) + ") " +
463  tree_manager, GetPointerS<const function_decl>(tree_manager->CGetTreeNode(caller_id)));
464 #endif
465  THROW_ASSERT(found, "call id " + STR(call_id) + " is not a call point in function " + caller_name +
466  " for function (" + STR(called_id) + ") " + called_name);
467  RemoveCallPoint(e, call_id);
468 }
469 
470 void CallGraphManager::ReplaceCallPoint(const EdgeDescriptor e, const unsigned int orig, const unsigned int repl)
471 {
472  THROW_ASSERT(orig != repl, "old call point is replaced with itself");
473  const auto caller_id = Cget_node_info<FunctionInfo, CallGraph>(boost::source(e, *call_graph), *call_graph)->nodeID;
474  const auto called_id = Cget_node_info<FunctionInfo, CallGraph>(boost::target(e, *call_graph), *call_graph)->nodeID;
475 
476  auto old_call_type = FunctionEdgeInfo::CallType::direct_call;
477  const auto edge_info = get_edge_info<FunctionEdgeInfo, CallGraph>(e, *call_graph);
478  const auto& direct_calls = edge_info->direct_call_points;
479  const auto& indirect_calls = edge_info->indirect_call_points;
480  const auto& function_addresses = edge_info->function_addresses;
481  const auto dir_it = direct_calls.find(orig);
482  if(dir_it != direct_calls.end())
483  {
485  }
486  const auto indir_it = indirect_calls.find(orig);
487  if(indir_it != indirect_calls.end())
488  {
490  }
491  const auto addr_it = function_addresses.find(orig);
492  if(addr_it != function_addresses.end())
493  {
495  }
496  // add goes before remove because it avoids clearing the edge
497  AddCallPoint(caller_id, called_id, repl, old_call_type);
498  RemoveCallPoint(e, orig);
499 }
500 
502 {
503  for(const auto i : addressed_functions)
504  {
506  {
507  return true;
508  }
509  }
510  return false;
511 }
512 
514 {
515  CustomSet<unsigned int> reachable_addressed_fun_ids;
516  std::set_intersection(reached_body_functions.cbegin(), reached_body_functions.cend(), addressed_functions.cbegin(),
517  addressed_functions.cend(),
518  std::inserter(reachable_addressed_fun_ids, reachable_addressed_fun_ids.begin()));
519  return reachable_addressed_fun_ids;
520 }
521 
523 {
525 }
526 
528 {
529  return call_graph;
530 }
531 
533 {
535 }
536 
537 vertex CallGraphManager::GetVertex(const unsigned int index) const
538 {
540  "this vertex does not exist " + STR(index));
541  return functionID_vertex_map.at(index);
542 }
543 
544 bool CallGraphManager::IsVertex(unsigned int functionID) const
545 {
546  return functionID_vertex_map.find(functionID) != functionID_vertex_map.end();
547 }
548 
549 unsigned int CallGraphManager::get_function(vertex node) const
550 {
551  return Cget_node_info<FunctionInfo, graph>(node, *call_graph)->nodeID;
552 }
553 
555 {
556  const auto it = called_by.find(index);
557  if(it != called_by.end())
558  {
559  return it->second;
560  }
561  return CustomSet<unsigned int>();
562 }
563 
565 {
566  return cfg->CGetOpNodeInfo(caller)->called;
567 }
568 
570 {
571  reached_body_functions.clear();
574  for(const auto root_id : root_functions)
575  {
576  if(IsVertex(root_id))
577  {
578  std::vector<boost::default_color_type> color_vec(boost::num_vertices(*call_graph));
579  auto other_root_functions = root_functions;
580  other_root_functions.erase(root_id);
581  const auto top_vertex = GetVertex(root_id);
582  boost::depth_first_visit(
583  *call_graph, top_vertex, vis,
584  boost::make_iterator_property_map(color_vec.begin(), boost::get(boost::vertex_index_t(), *call_graph),
585  boost::white_color),
586  [&](vertex u, const CallGraph& g) {
587  return other_root_functions.find(Cget_node_info<FunctionInfo, graph>(u, g)->nodeID) !=
588  other_root_functions.end();
589  });
590  }
591  }
592 }
593 
595 {
596  root_functions = _root_functions;
597 }
598 
600 {
601  THROW_ASSERT(boost::num_vertices(*call_graph) == 0 || root_functions.size(),
602  "Root functions have not yet been computed");
603  return root_functions;
604 }
605 
607 {
608  return reached_body_functions;
609 }
610 
612 {
615 
616  const auto top_vertex = GetVertex(from);
617  CalledFunctionsVisitor vis(allow_recursive_functions, this, f_list, with_body ? dummy : f_list);
618  std::vector<boost::default_color_type> color_vec(boost::num_vertices(*call_graph));
619  auto other_root_functions = root_functions;
620  other_root_functions.erase(from);
621  boost::depth_first_visit(*call_graph, top_vertex, vis,
622  boost::make_iterator_property_map(color_vec.begin(),
623  boost::get(boost::vertex_index_t(), *call_graph),
624  boost::white_color),
625  [&](vertex u, const CallGraph& g) {
626  return other_root_functions.find(Cget_node_info<FunctionInfo, graph>(u, g)->nodeID) !=
627  other_root_functions.end();
628  });
629  return f_list;
630 }
631 
632 unsigned int CallGraphManager::GetRootFunction(unsigned int fid) const
633 {
634  if(root_functions.find(fid) != root_functions.end())
635  {
636  return fid;
637  }
638 
639  unsigned int parent_fid = 0;
640  const auto top_vertex = GetVertex(fid);
641  for(auto root_fid : root_functions)
642  {
644  CalledFunctionsVisitor vis(allow_recursive_functions, this, f_list, f_list);
645  std::vector<boost::default_color_type> color_vec(boost::num_vertices(*call_graph));
646  auto other_root_functions = root_functions;
647  other_root_functions.erase(fid);
648  boost::depth_first_visit(*call_graph, top_vertex, vis,
649  boost::make_iterator_property_map(color_vec.begin(),
650  boost::get(boost::vertex_index_t(), *call_graph),
651  boost::white_color),
652  [&](vertex u, const CallGraph& g) {
653  return other_root_functions.find(Cget_node_info<FunctionInfo, graph>(u, g)->nodeID) !=
654  other_root_functions.end();
655  });
656  if(f_list.find(fid) != f_list.end())
657  {
658  THROW_ASSERT(parent_fid == 0, "Expected single parent root functions.");
659 #if HAVE_ASSERTS
660  parent_fid = root_fid;
661 #else
662  return root_fid;
663 #endif
664  }
665  }
666  return parent_fid;
667 }
668 
670 {
672 }
673 
675  const application_managerRef AM, unsigned int f_id, int DL)
676 {
677  const auto TM = AM->get_tree_manager();
678  const auto has_body = TM->get_implementation_node(f_id) != 0;
679  if(has_body)
680  {
681  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, DL, "---Analyze body of " + tree_helper::name_function(TM, f_id));
682  const auto fun = TM->CGetTreeNode(f_id);
683  const auto fd = GetPointerS<const function_decl>(fun);
684  const auto sl = GetPointerS<const statement_list>(GET_NODE(fd->body));
685  if(sl->list_of_bloc.empty())
686  {
687  THROW_ERROR("We can only work on CFG provided by GCC/CLANG");
688  }
689  else
690  {
691  for(const auto& b : sl->list_of_bloc)
692  {
693  for(const auto& stmt : b.second->CGetStmtList())
694  {
695  call_graph_computation_recursive(AV, AM, f_id, TM, stmt, stmt->index,
697  }
698  }
699  }
700  }
701 }
703  unsigned int caller_id, unsigned int called_id, unsigned int call_id,
704  enum FunctionEdgeInfo::CallType call_type, int DL)
705 {
706  bool has_been_previously_added = AM->GetCallGraphManager()->IsVertex(called_id);
707  AM->GetCallGraphManager()->AddFunctionAndCallPoint(AM, caller_id, called_id, call_id, call_type);
708  if(!has_been_previously_added)
709  {
710  expandCallGraphFromFunction(AV, AM, called_id, DL);
711  }
712 }
713 
715  const application_managerRef AM, unsigned int current,
716  const tree_managerRef& TM, const tree_nodeRef& tn,
717  unsigned int node_stmt,
718  enum FunctionEdgeInfo::CallType call_type, int DL)
719 {
720  THROW_ASSERT(tn->get_kind() == tree_reindex_K, "Node is not a tree reindex");
721  const tree_nodeRef& curr_tn = GET_NODE(tn);
722  unsigned int ind = GET_INDEX_NODE(tn);
723  if(curr_tn->get_kind() != function_decl_K)
724  {
725  if(AV.find(ind) != AV.end())
726  {
727  return;
728  }
729  else
730  {
731  AV.insert(ind);
732  }
733  }
735  "-->Recursive analysis of " + STR(ind) + " of type " + curr_tn->get_kind_text() + "(statement is " +
736  tn->ToString() + ")");
737 
738  switch(curr_tn->get_kind())
739  {
740  case function_decl_K:
741  {
742  unsigned int impl = TM->get_implementation_node(ind);
743  if(impl)
744  {
745  ind = impl;
746  }
748  const tree_nodeRef fun = TM->get_tree_node_const(ind);
749  const auto* fd = GetPointer<const function_decl>(fun);
750  if(fd->scpe && GET_NODE(fd->scpe)->get_kind() == function_decl_K)
751  {
752  THROW_ERROR_CODE(NESTED_FUNCTIONS_EC, "Nested functions not yet supported " + STR(ind));
753  THROW_ERROR("Nested functions not yet supported " + STR(ind));
754  }
755  AM->GetCallGraphManager()->AddFunctionAndCallPoint(AM, current, ind, node_stmt, call_type);
756  if(AV.find(ind) != AV.end())
757  {
759  return;
760  }
761  else
762  {
763  AV.insert(ind);
764  }
765  expandCallGraphFromFunction(AV, AM, ind, DL);
766  break;
767  }
768  case gimple_return_K:
769  {
770  auto* re = GetPointer<gimple_return>(curr_tn);
771  if(re->op)
772  {
773  call_graph_computation_recursive(AV, AM, current, TM, re->op, node_stmt, call_type, DL);
774  }
775  break;
776  }
777  case gimple_assign_K:
778  {
779  auto* me = GetPointer<gimple_assign>(curr_tn);
780 
781  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, DL, "---Analyzing left part");
782  call_graph_computation_recursive(AV, AM, current, TM, me->op0, node_stmt, call_type, DL);
783  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, DL, "---Analyzed left part - Analyzing right part");
784  call_graph_computation_recursive(AV, AM, current, TM, me->op1, node_stmt, call_type, DL);
785  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, DL, "---Analyzed right part");
786  if(me->predicate)
787  {
788  call_graph_computation_recursive(AV, AM, current, TM, me->predicate, node_stmt, call_type, DL);
789  }
790  break;
791  }
792  case gimple_nop_K:
793  {
794  break;
795  }
796  case aggr_init_expr_K:
797  case call_expr_K:
798  {
799  auto* ce = GetPointer<call_expr>(curr_tn);
800  tree_nodeRef fun_node = GET_NODE(ce->fn);
801  if(fun_node->get_kind() == addr_expr_K)
802  {
803  auto* ue = GetPointer<unary_expr>(fun_node);
804  fun_node = ue->op;
805  }
806  else if(fun_node->get_kind() == obj_type_ref_K)
807  {
808  fun_node = tree_helper::find_obj_type_ref_function(ce->fn);
809  }
810  else
811  {
812  fun_node = ce->fn;
813  }
814 
815  call_graph_computation_recursive(AV, AM, current, TM, fun_node, node_stmt,
817  for(auto& arg : ce->args)
818  {
819  call_graph_computation_recursive(AV, AM, current, TM, arg, node_stmt, call_type, DL);
820  }
821  break;
822  }
823  case gimple_call_K:
824  {
825  auto* ce = GetPointer<gimple_call>(curr_tn);
826  tree_nodeRef fun_node = GET_NODE(ce->fn);
827  if(fun_node->get_kind() == addr_expr_K)
828  {
829  auto* ue = GetPointer<unary_expr>(fun_node);
830  fun_node = ue->op;
831  }
832  else if(fun_node->get_kind() == obj_type_ref_K)
833  {
834  fun_node = tree_helper::find_obj_type_ref_function(ce->fn);
835  }
836  else
837  {
838  fun_node = ce->fn;
839  }
840  call_graph_computation_recursive(AV, AM, current, TM, fun_node, node_stmt,
842  for(auto& arg : ce->args)
843  {
844  call_graph_computation_recursive(AV, AM, current, TM, arg, node_stmt, call_type, DL);
845  }
846  break;
847  }
848  case cond_expr_K:
849  {
850  auto* ce = GetPointer<cond_expr>(curr_tn);
851  call_graph_computation_recursive(AV, AM, current, TM, ce->op0, node_stmt, call_type, DL);
852  call_graph_computation_recursive(AV, AM, current, TM, ce->op1, node_stmt, call_type, DL);
853  call_graph_computation_recursive(AV, AM, current, TM, ce->op2, node_stmt, call_type, DL);
854  break;
855  }
856  case gimple_cond_K:
857  {
858  auto* gc = GetPointer<gimple_cond>(curr_tn);
859  call_graph_computation_recursive(AV, AM, current, TM, gc->op0, node_stmt, call_type, DL);
860  break;
861  }
862  /* Unary expressions. */
864  {
865  auto* ue = GetPointer<unary_expr>(curr_tn);
866  call_graph_computation_recursive(AV, AM, current, TM, ue->op, node_stmt, call_type, DL);
867  break;
868  }
870  {
871  auto* be = GetPointer<binary_expr>(curr_tn);
872  call_graph_computation_recursive(AV, AM, current, TM, be->op0, node_stmt, call_type, DL);
873  call_graph_computation_recursive(AV, AM, current, TM, be->op1, node_stmt, call_type, DL);
874  break;
875  }
876  /*ternary expressions*/
877  case gimple_switch_K:
878  {
879  auto* se = GetPointer<gimple_switch>(curr_tn);
880  call_graph_computation_recursive(AV, AM, current, TM, se->op0, node_stmt, call_type, DL);
881  break;
882  }
883  case gimple_multi_way_if_K:
884  {
885  auto* gmwi = GetPointer<gimple_multi_way_if>(curr_tn);
886  for(const auto& cond : gmwi->list_of_cond)
887  {
888  if(cond.first)
889  {
890  call_graph_computation_recursive(AV, AM, current, TM, cond.first, node_stmt, call_type, DL);
891  }
892  }
893  break;
894  }
895  case obj_type_ref_K:
896  {
898  call_graph_computation_recursive(AV, AM, current, TM, fun, node_stmt, call_type, DL);
899  break;
900  }
901  case save_expr_K:
902  case component_ref_K:
903  case bit_field_ref_K:
904  case vtable_ref_K:
905  case with_cleanup_expr_K:
906  case vec_cond_expr_K:
907  case vec_perm_expr_K:
908  case dot_prod_expr_K:
909  case ternary_plus_expr_K:
910  case ternary_pm_expr_K:
911  case ternary_mp_expr_K:
912  case ternary_mm_expr_K:
913  case fshl_expr_K:
914  case fshr_expr_K:
915  case insertvalue_expr_K:
916  case insertelement_expr_K:
917  case bit_ior_concat_expr_K:
918  {
919  auto* te = GetPointer<ternary_expr>(curr_tn);
920  call_graph_computation_recursive(AV, AM, current, TM, te->op0, node_stmt, call_type, DL);
921  call_graph_computation_recursive(AV, AM, current, TM, te->op1, node_stmt, call_type, DL);
922  if(te->op2)
923  {
924  call_graph_computation_recursive(AV, AM, current, TM, te->op2, node_stmt, call_type, DL);
925  }
926  break;
927  }
929  {
930  auto* qe = GetPointer<quaternary_expr>(curr_tn);
931  call_graph_computation_recursive(AV, AM, current, TM, qe->op0, node_stmt, call_type, DL);
932  call_graph_computation_recursive(AV, AM, current, TM, qe->op1, node_stmt, call_type, DL);
933  if(qe->op2)
934  {
935  call_graph_computation_recursive(AV, AM, current, TM, qe->op2, node_stmt, call_type, DL);
936  }
937  if(qe->op3)
938  {
939  call_graph_computation_recursive(AV, AM, current, TM, qe->op3, node_stmt, call_type, DL);
940  }
941  break;
942  }
943  case lut_expr_K:
944  {
945  auto* le = GetPointer<lut_expr>(curr_tn);
946  call_graph_computation_recursive(AV, AM, current, TM, le->op0, node_stmt, call_type, DL);
947  call_graph_computation_recursive(AV, AM, current, TM, le->op1, node_stmt, call_type, DL);
948  if(le->op2)
949  {
950  call_graph_computation_recursive(AV, AM, current, TM, le->op2, node_stmt, call_type, DL);
951  }
952  if(le->op3)
953  {
954  call_graph_computation_recursive(AV, AM, current, TM, le->op3, node_stmt, call_type, DL);
955  }
956  if(le->op4)
957  {
958  call_graph_computation_recursive(AV, AM, current, TM, le->op4, node_stmt, call_type, DL);
959  }
960  if(le->op5)
961  {
962  call_graph_computation_recursive(AV, AM, current, TM, le->op5, node_stmt, call_type, DL);
963  }
964  if(le->op6)
965  {
966  call_graph_computation_recursive(AV, AM, current, TM, le->op6, node_stmt, call_type, DL);
967  }
968  if(le->op7)
969  {
970  call_graph_computation_recursive(AV, AM, current, TM, le->op7, node_stmt, call_type, DL);
971  }
972  if(le->op8)
973  {
974  call_graph_computation_recursive(AV, AM, current, TM, le->op8, node_stmt, call_type, DL);
975  }
976  break;
977  }
978  case constructor_K:
979  {
980  auto* c = GetPointer<constructor>(curr_tn);
981  for(const auto& i : c->list_of_idx_valu)
982  {
983  call_graph_computation_recursive(AV, AM, current, TM, i.second, node_stmt, call_type, DL);
984  }
985  break;
986  }
987  case var_decl_K:
988  {
990  auto* vd = GetPointer<var_decl>(curr_tn);
991  if(vd->init)
992  {
993  call_graph_computation_recursive(AV, AM, current, TM, vd->init, node_stmt, call_type, DL);
994  }
995  }
996  case result_decl_K:
997  case parm_decl_K:
998  case ssa_name_K:
999  case integer_cst_K:
1000  case real_cst_K:
1001  case string_cst_K:
1002  case vector_cst_K:
1003  case void_cst_K:
1004  case complex_cst_K:
1005  case field_decl_K:
1006  case label_decl_K:
1007  case template_decl_K:
1008  case gimple_label_K:
1009  case gimple_goto_K:
1010  case gimple_asm_K:
1011  case gimple_phi_K:
1012  case target_mem_ref_K:
1013  case target_mem_ref461_K:
1014  case CASE_PRAGMA_NODES:
1015  case gimple_pragma_K:
1016  {
1017  break;
1018  }
1019  case binfo_K:
1020  case block_K:
1021  case CASE_CPP_NODES:
1022  case case_label_expr_K:
1023  case CASE_FAKE_NODES:
1024  case const_decl_K:
1025  case gimple_bind_K:
1026  case gimple_for_K:
1027  case gimple_predict_K:
1028  case gimple_resx_K:
1029  case gimple_while_K:
1030  case identifier_node_K:
1031  case namespace_decl_K:
1032  case statement_list_K:
1033  case translation_unit_decl_K:
1034  case error_mark_K:
1035  case using_decl_K:
1036  case tree_list_K:
1037  case tree_vec_K:
1038  case type_decl_K:
1039  case target_expr_K:
1040  case CASE_TYPE_NODES:
1041  {
1042  THROW_ERROR(std::string("Node not supported (") + STR(ind) + std::string("): ") + curr_tn->get_kind_text());
1043  break;
1044  }
1045  default:
1046  THROW_UNREACHABLE("");
1047  };
1048  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, DL, "<--Completed the recursive analysis of node " + STR(ind));
1049 }
#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 STD_SELECTOR
Definition: call_graph.hpp:60
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
CustomSet< unsigned int > & body_functions
The list of encountered body functions.
bool IsCallPoint(unsigned int caller_id, unsigned int called_id, unsigned int call_id, enum FunctionEdgeInfo::CallType call_type) const
Returns true if the call point is present.
const CustomSet< unsigned int > & GetReachedBodyFunctions() const
Returns the source code functions called by the root functions.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
static std::string name_function(const tree_managerConstRef &tm, const unsigned int index)
Return the name of the function.
refcount< CallGraph > CallGraphRef
The refcount definition for CallGraph.
Definition: call_graph.hpp:218
File containing functions and utilities to support the printing of debug messagges.
const bool allow_recursive_functions
True if recursive calls are allowed.
std::string ToString() const
Print this node as string in gimple format.
CustomSet< unsigned int > GetRootFunctions() const
Returns the root functions (i.e., the functions that are not called by any other ones.
#define DEBUG_LEVEL_PEDANTIC
very verbose debugging print is performed.
#define CASE_BINARY_EXPRESSION
This macro collects all case labels for binary_expr objects.
Definition: tree_node.hpp:463
string target
Definition: lenet_tvm.py:16
#define GET_CLASS(obj)
Macro returning the actual type of an object.
Definition of the class representing a generic C application.
#define GET_NODE_INFO(data, NodeInfo, vertex_index)
Definition: graph.hpp:601
CustomSet< unsigned int > reached_body_functions
source code functions directly or indirectly called by the root functions
refcount< BehavioralHelper > BehavioralHelperRef
RefCount type definition of the tree_to_graph class structure.
This class manages the tree structures extracted from the raw file.
CustomSet< unsigned int > addressed_functions
set of functions whose address is taken
Class specification of the graph structures.
exceptions managed by PandA
void back_edge(const EdgeDescriptor &e, const CallGraph &g)
#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
static std::string print_function_name(const tree_managerConstRef &TM, const function_decl *fd)
Return the name of the function in a string.
CallGraphManager(const FunctionExpanderConstRef function_expander, const bool allow_recursive_functions, const tree_managerConstRef tree_manager, const ParameterConstRef Param)
Constructor.
Data structure describing a basic block at tree level.
CustomSet< unsigned int > GetAddressedFunctions() const
Returns a set containing all the reachable addressed_functions.
std::map< unsigned int, vertex > functionID_vertex_map
put into relation function F_i and the vertex in the call graph representing it
Information associated with a call_graph node.
Definition: call_graph.hpp:66
CustomSet< unsigned int > root_functions
Root functions.
const tree_nodeConstRef CGetTreeNode(const unsigned int i) const
virtual enum kind get_kind() const =0
Virtual function returning the type of the actual class.
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
#define FEEDBACK_SELECTOR
Definition: call_graph.hpp:61
unsigned int get_function(vertex node) const
Given a vertex of the call graph, this returns the index of the corresponding function.
The info associated with the call graph.
Definition: call_graph.hpp:106
static void addCallPointAndExpand(CustomUnorderedSet< unsigned int > &AV, const application_managerRef AM, unsigned int caller_id, unsigned int called_id, unsigned int call_id, enum FunctionEdgeInfo::CallType call_type, int DL)
const tree_nodeRef get_tree_node_const(unsigned int i) const
Return the reference to the i-th tree_node Constant version of get_tree_node.
This class is the view of a call graph.
Definition: call_graph.hpp:160
CalledFunctionsVisitor(const bool _allow_recursive_functions, const CallGraphManager *_call_graph_manager, CustomSet< unsigned int > &_body_functions, CustomSet< unsigned int > &_library_functions)
Constructor.
const OpNodeInfoConstRef CGetOpNodeInfo(const vertex node) const
Returns the info associated with a node.
Definition: op_graph.hpp:843
void finish_vertex(const vertex &u, const CallGraph &g)
Function called when a vertex has been finished.
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
const bool allow_recursive_functions
True if recursive calls are allowed.
std::map< unsigned int, CustomSet< unsigned int > > called_by
put into relation function F_i and the list of functions called by F_i
#define CASE_QUATERNARY_EXPRESSION
This macro collects all case labels for quaternary_expr objects.
Definition: tree_node.hpp:574
#define CASE_UNARY_EXPRESSION
This macro collects all case labels for unary_expr objects.
Definition: tree_node.hpp:371
static void call_graph_computation_recursive(CustomUnorderedSet< unsigned int > &AV, const application_managerRef AM, unsigned int current, const tree_managerRef &TM, const tree_nodeRef &tn, unsigned int node_stmt, enum FunctionEdgeInfo::CallType call_type, int DL)
Recursive analysis of the tree nodes looking for call expressions.
CustomSet< unsigned int > reached_library_functions
library functions directly or indirectly called by the root functions
#define index(x, y)
Definition: Keccak.c:74
This class collects information concerning the set of functions that will be analyzed by the PandA fr...
Definition: call_graph.hpp:119
void ReplaceCallPoint(const EdgeDescriptor e, const unsigned int orig, const unsigned int repl)
Replaces a call point.
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
void AddCallPoint(unsigned int caller_id, unsigned int called_id, unsigned int call_id, enum FunctionEdgeInfo::CallType call_type)
Creates a new call point.
unsigned int get_implementation_node(unsigned int decl_node) const
Return the index of function_decl node that implements the declaration node.
CallGraphConstRef CGetCallGraph() const
Return the call graph.
Classes specification of the tree_node data structures.
Call graph hierarchy.
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
refcount< NodeInfo > NodeInfoRef
RefCount type definition of the NodeInfo class structure.
Definition: node_info.hpp:98
#define CASE_TYPE_NODES
This macro collects all case labels for type objects.
Definition: tree_node.hpp:581
This file collects some utility functions.
refcount< FunctionBehavior > FunctionBehaviorRef
void TopologicalSort(std::list< boost::graph_traits< graphs_collection >::vertex_descriptor > &sorted_vertices) const
Compute the topological order of the graph.
Definition: graph.hpp:996
static tree_nodeRef find_obj_type_ref_function(const tree_nodeConstRef &tn)
Given the tree_node of an obj_type_ref return the tree_node of the called function.
bool ExistsAddressedFunction() const
Returns true is there is at least a reachable function that is called through a function pointer or i...
refcount< const CallGraph > CallGraphConstRef
Definition: call_graph.hpp:219
CustomSet< unsigned int > GetReachedFunctionsFrom(unsigned int from_f, bool with_body=true) const
compute the list of reached function starting from a given function
const int debug_level
the debug level
void AddFunctionAndCallPoint(unsigned int caller_id, unsigned int called_id, unsigned int call_id, const FunctionBehaviorRef called_function_behavior, enum FunctionEdgeInfo::CallType call_type)
Creates a new called function and directly adds the call to the call graph.
CustomSet< unsigned int > get_called_by(unsigned int index) const
Returns the set of functions called by a function.
Class specification of the tree_reindex support class.
Visitor to identify the list of called functions.
#define CASE_FAKE_NODES
This macro collects all case labels for fake or empty nodes.
Definition: tree_node.hpp:635
CustomSet< unsigned int > & library_functions
The list of encountered library functions.
CustomSet< unsigned int > GetReachedLibraryFunctions() const
Returns the library functions called by the root functions.
~CallGraphManager()
Destructor.
This class manages the accesses to the CallGraph.
void RemoveCallPoint(const unsigned int caller_id, const unsigned int called_id, const unsigned int call_id)
Remove a function call, like RemoveCallPoint with a different API.
Data structures used in operations graph.
T * get() const
Definition: refcount.hpp:169
void ComputeRootAndReachedFunctions()
Compute the root and reached functions, maintaining the internal data structures coherent.
#define THROW_ERROR_CODE(code, str_expr)
helper function used to throw an error with a code error
Definition: exceptions.hpp:266
interface of loops finding algorithm
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.
#define CASE_CPP_NODES
This macro collects all case labels for cpp nodes.
Definition: tree_node.hpp:644
nested functions are not currently supported
Definition: exceptions.hpp:325
unsigned int GetRootFunction(unsigned int fid) const
Get the parent root function.
Wrapper to call graph.
CallGraphConstRef CGetCallSubGraph(const CustomUnorderedSet< vertex > &vertices) const
Return a subset of the call graph.
void AddFunction(unsigned int new_function_id, const FunctionBehaviorRef fun_behavior)
int fun(float *A, float *invA, float *b, float *x, float *I)
vertex GetVertex(const unsigned int index) const
Return the vertex given the function id.
CallGraphConstRef CGetAcyclicCallGraph() const
Return an acyclic version of the call graph.
bool IsVertex(unsigned int functionID) const
return true in case the vertex has been already created
void SetRootFunctions(const CustomSet< unsigned int > &root_functions)
Set the root functions.
const CallGraphManager * call_graph_manager
The call graph manager.
const CallGraphInfoConstRef CGetCallGraphInfo() const
Return the info associated with the call graph.
Definition: call_graph.hpp:197
const CallGraphsCollectionRef call_graphs_collection
static void expandCallGraphFromFunction(CustomUnorderedSet< unsigned int > &AV, const application_managerRef AM, unsigned int f_id, int DL)
const CallGraphRef call_graph
The view of call graph with all the edges.
Class specification of the manager of the tree structures extracted from the raw file.
A brief description of the C++ Header File.
int sl
Definition: adpcm.c:105
#define CASE_PRAGMA_NODES
This macro collects all case labels for pragma objects.
Definition: tree_node.hpp:610
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:50 for PandA-2024.02 by doxygen 1.8.13