PandA-2024.02
dead_code_eliminationIPA.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) 2016-2024 Politecnico di Milano
16  *
17  * This file is part of the PandA framework.
18  *
19  * The PandA framework is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 3 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program. If not, see <http://www.gnu.org/licenses/>.
31  *
32  */
44 
45 #include "Parameter.hpp"
46 #include "application_manager.hpp"
47 #include "behavioral_helper.hpp"
48 #include "call_graph.hpp"
49 #include "call_graph_manager.hpp"
50 #include "custom_map.hpp"
51 #include "custom_set.hpp"
52 #include "dbgPrintHelper.hpp"
53 #include "design_flow_graph.hpp"
54 #include "design_flow_manager.hpp"
55 #include "function_behavior.hpp"
57 #include "hls_manager.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_manipulation.hpp"
63 #include "tree_node.hpp"
64 #include "tree_reindex.hpp"
65 #include "utility.hpp"
66 #include "var_pp_functor.hpp"
67 
68 #include <string>
69 #include <utility>
70 
71 dead_code_eliminationIPA::dead_code_eliminationIPA(const application_managerRef AM, const DesignFlowManagerConstRef dfm,
72  const ParameterConstRef par)
73  : ApplicationFrontendFlowStep(AM, DEAD_CODE_ELIMINATION_IPA, dfm, par)
74 {
75  debug_level = parameters->get_class_debug_level(GET_CLASS(*this), DEBUG_LEVEL_NONE);
76 }
77 
79 
82 {
84  switch(relationship_type)
85  {
87  {
88  relationships.insert(std::make_pair(DEAD_CODE_ELIMINATION, ALL_FUNCTIONS));
89  relationships.insert(std::make_pair(PARM2SSA, ALL_FUNCTIONS));
90  break;
91  }
93  {
94  if(!parameters->getOption<int>(OPT_gcc_openmp_simd))
95  {
96  relationships.insert(std::make_pair(BIT_VALUE_OPT, ALL_FUNCTIONS));
97  }
98  break;
99  }
101  {
102  break;
103  }
104  default:
105  {
106  THROW_UNREACHABLE("");
107  }
108  }
109  return relationships;
110 }
111 
113  const DesignFlowStep::RelationshipType relationship_type)
114 {
115  if(relationship_type == INVALIDATION_RELATIONSHIP)
116  {
117  const auto DFM = design_flow_manager.lock();
118  const auto DFG = DFM->CGetDesignFlowGraph();
119  std::vector<FrontendFlowStepType> step_types = {FrontendFlowStepType::DEAD_CODE_ELIMINATION};
120  if(!parameters->getOption<int>(OPT_gcc_openmp_simd))
121  {
122  step_types.push_back(FrontendFlowStepType::BIT_VALUE);
123  }
124  for(const auto i : fun_id_to_restart)
125  {
126  for(auto step_type : step_types)
127  {
128  const auto step_signature = FunctionFrontendFlowStep::ComputeSignature(step_type, i);
129  const auto frontend_step = DFM->GetDesignFlowStep(step_signature);
130  THROW_ASSERT(frontend_step != NULL_VERTEX, "step " + step_signature + " is not present");
131  const auto design_flow_step = DFG->CGetDesignFlowStepInfo(frontend_step)->design_flow_step;
132  relationships.insert(design_flow_step);
133  }
134  }
135  fun_id_to_restart.clear();
136  for(const auto i : fun_id_to_restartParm)
137  {
138  const auto step_signature = FunctionFrontendFlowStep::ComputeSignature(FrontendFlowStepType::PARM2SSA, i);
139  const auto frontend_step = DFM->GetDesignFlowStep(step_signature);
140  THROW_ASSERT(frontend_step != NULL_VERTEX, "step " + step_signature + " is not present");
141  const auto design_flow_step = DFG->CGetDesignFlowStepInfo(frontend_step)->design_flow_step;
142  relationships.insert(design_flow_step);
143  }
144  fun_id_to_restartParm.clear();
145  }
146  ApplicationFrontendFlowStep::ComputeRelationships(relationships, relationship_type);
147 }
148 
150 {
151  return true;
152 }
153 
155 {
156  if(!AppM->ApplyNewTransformation())
157  {
159  }
160  fun_id_to_restart.clear();
161  fun_id_to_restartParm.clear();
162  const auto TM = AppM->get_tree_manager();
163  const auto CGM = AppM->CGetCallGraphManager();
164  CustomSet<unsigned int> interface_functions;
165  {
166  const auto top_functions = parameters->getOption<std::vector<std::string>>(OPT_top_functions_names);
167  std::transform(top_functions.begin(), top_functions.end(),
168  std::inserter(interface_functions, interface_functions.end()),
169  [&](const auto& fname) { return GET_INDEX_CONST_NODE(TM->GetFunction(fname)); });
170  const auto addr_funcs = CGM->GetAddressedFunctions();
171  interface_functions.insert(addr_funcs.begin(), addr_funcs.end());
172  }
173  const auto reached_body_fun_ids = CGM->GetReachedBodyFunctions();
174  for(const auto f_id : reached_body_fun_ids)
175  {
176  const auto is_root = interface_functions.find(f_id) != interface_functions.end();
177  if(!is_root)
178  {
179  const auto fu_name = AppM->CGetFunctionBehavior(f_id)->CGetBehavioralHelper()->get_function_name();
181  "-->Analyzing function \"" + fu_name + "\": id = " + STR(f_id));
182  const auto fu_node = TM->GetTreeNode(f_id);
183  auto fd = GetPointerS<function_decl>(fu_node);
184  THROW_ASSERT(fd && fd->body, "Node is not a function or it hasn't a body");
185  if(!fd->list_of_args.empty())
186  {
187  signature_opt(TM, fd, f_id, reached_body_fun_ids);
188  }
189  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--Analyzed function ");
190  }
191  }
192  for(auto& f_id : fun_id_to_restart)
193  {
194  const auto FB = AppM->GetFunctionBehavior(f_id);
195  FB->UpdateBBVersion();
196  }
197  for(auto& f_id : fun_id_to_restartParm)
198  {
199  const auto FB = AppM->GetFunctionBehavior(f_id);
200  FB->UpdateBBVersion();
201  }
202  return fun_id_to_restart.empty() && fun_id_to_restartParm.empty() ? DesignFlowStep_Status::UNCHANGED :
204 }
205 
206 bool dead_code_eliminationIPA::signature_opt(const tree_managerRef& TM, function_decl* fd, unsigned int function_id,
207  const CustomOrderedSet<unsigned int>& rFunctions)
208 {
209  const auto& parms = fd->list_of_args;
210  std::vector<unsigned int> unused_parm_indices;
211  {
212  auto idx = static_cast<unsigned int>(parms.size() - 1);
213  for(auto it = parms.rbegin(); it != parms.rend(); ++it, --idx)
214  {
215  const auto ssa = AppM->getSSAFromParm(function_id, GET_INDEX_CONST_NODE(*it));
216  if(GetPointer<const ssa_name>(TM->CGetTreeNode(ssa))->CGetUseStmts().empty())
217  {
218  unused_parm_indices.push_back(idx);
219  }
220  }
221  }
223  if(unused_parm_indices.empty())
224  {
225  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "No unused parameter found");
227  return false;
228  }
229 
231  "Unused parameter indices: " +
232  container_to_string(unused_parm_indices.rbegin(), unused_parm_indices.rend(), ", ", false));
233  const auto arg_eraser = [&](std::vector<tree_nodeRef>& arg_list, const tree_nodeRef& call_stmt) {
234  for(const auto& idx : unused_parm_indices)
235  {
236  const auto arg_it = std::next(arg_list.begin(), idx);
237  auto ssa = GetPointer<ssa_name>(GET_NODE(*arg_it));
238  if(ssa)
239  {
240  THROW_ASSERT(ssa->CGetUseStmts().count(call_stmt),
241  "ssa " + ssa->ToString() + " not used in " + call_stmt->ToString());
242 
243  if(ssa->virtual_flag)
244  {
245  const auto gn = GetPointerS<gimple_node>(GET_NODE(call_stmt));
246  if(gn->vuses.erase(*arg_it))
247  {
248  ssa->RemoveUse(call_stmt);
249  }
250  if(gn->vovers.erase(*arg_it))
251  {
252  ssa->RemoveUse(call_stmt);
253  }
254  }
255  else
256  {
257  ssa->RemoveUse(call_stmt);
258  }
259  }
260  arg_list.erase(arg_it);
261  }
262  };
263  const auto CGM = AppM->CGetCallGraphManager();
264  const auto CG = CGM->CGetCallGraph();
265  const auto function_v = CGM->GetVertex(function_id);
266 
268  std::vector<tree_nodeRef> loa = fd->list_of_args;
269  std::vector<tree_nodeConstRef> argsT;
270  arg_eraser(loa, nullptr);
271  std::transform(loa.cbegin(), loa.cend(), std::back_inserter(argsT),
272  [&](const tree_nodeRef& arg) { return tree_helper::CGetType(arg); });
273  const auto ftype = tree_man->GetFunctionType(tree_helper::GetFunctionReturnType(fd->type, false), argsT);
274  const auto ftype_ptr = tree_man->GetPointerType(ftype);
275  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Erasing unused arguments from call points");
277  BOOST_FOREACH(EdgeDescriptor ie, boost::in_edges(function_v, *CG))
278  {
279  const auto caller_id = CGM->get_function(ie.m_source);
280  if(rFunctions.find(caller_id) != rFunctions.end())
281  {
282  const auto fei = CG->CGetFunctionEdgeInfo(ie);
285  "Analysing call points from " +
286  tree_helper::GetMangledFunctionName(GetPointerS<const function_decl>(TM->CGetTreeNode(caller_id))));
287  for(const auto& call_id : fei->direct_call_points)
288  {
289  auto call_rdx = TM->GetTreeReindex(call_id);
290  auto call_stmt = GET_NODE(call_rdx);
291  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Before: " + call_stmt->ToString());
292  tree_nodeRef fn;
293  if(call_stmt->get_kind() == gimple_call_K)
294  {
295  auto gc = GetPointerS<gimple_call>(call_stmt);
296  THROW_ASSERT(gc->args.size() == parms.size(), "");
297  fn = gc->fn;
298  arg_eraser(gc->args, call_rdx);
299  }
300  else if(call_stmt->get_kind() == gimple_assign_K)
301  {
302  const auto ga = GetPointerS<const gimple_assign>(call_stmt);
303  auto ce = GetPointer<call_expr>(GET_NODE(ga->op1));
304  fn = ce->fn;
305  THROW_ASSERT(ce, "Unexpected call expression: " + GET_NODE(ga->op1)->get_kind_text());
306  THROW_ASSERT(ce->args.size() == parms.size(), "");
307  arg_eraser(ce->args, call_rdx);
308  }
309  else
310  {
311  THROW_UNREACHABLE("Call point statement not handled: " + call_stmt->get_kind_text());
312  }
313  auto ae = GetPointer<addr_expr>(GET_NODE(fn));
314  if(ae)
315  {
316  ae->type = ftype_ptr;
317  }
318  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---After : " + call_stmt->ToString());
319  }
320  THROW_ASSERT(fei->indirect_call_points.empty(), "");
321  THROW_ASSERT(fei->function_addresses.empty(), "");
322  fun_id_to_restart.insert(caller_id);
323  }
324  }
325  fun_id_to_restart.insert(function_id);
326  fun_id_to_restartParm.insert(function_id);
328  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Erasing unused parameters from function signature");
331  "---Before: " +
332  tree_helper::print_type(TM, function_id, false, true, false, 0U,
334  AppM->CGetFunctionBehavior(function_id)->CGetBehavioralHelper()))));
335  const auto HLSMgr = GetPointer<HLS_manager>(AppM);
336  const auto fname = tree_helper::GetMangledFunctionName(fd);
337  const auto func_arch = HLSMgr->module_arch->GetArchitecture(fname);
338  if(func_arch)
339  {
340  for(auto i : unused_parm_indices)
341  {
342  const auto& pnode = fd->list_of_args.at(i);
343  const auto pname = GetPointer<parm_decl>(GET_NODE(pnode))->name;
344  THROW_ASSERT(pname, "Expected parameter name.");
345  const auto pname_str = GetPointer<identifier_node>(GET_NODE(pname))->strg;
346  func_arch->parms.erase(pname_str);
347  }
348  }
349  fd->list_of_args = loa;
350  fd->type = ftype;
352  "---After : " +
353  tree_helper::print_type(TM, function_id, false, true, false, 0U,
355  AppM->CGetFunctionBehavior(function_id)->CGetBehavioralHelper()))));
358  return true;
359 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
DesignFlowStep_Status Exec() override
Execute the step.
#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;.
File containing functions and utilities to support the printing of debug messagges.
#define DEBUG_LEVEL_PEDANTIC
very verbose debugging print is performed.
Step successfully executed.
#define GET_CLASS(obj)
Macro returning the actual type of an object.
Definition of the class representing a generic C application.
static std::string print_type(const tree_managerConstRef &TM, unsigned int type, bool global=false, bool print_qualifiers=false, bool print_storage=false, unsigned int var=0, const var_pp_functorConstRef &vppf=var_pp_functorConstRef(), const std::string &prefix="", const std::string &tail="")
Print a type and its variable in case var is not zero.
RelationshipType
The relationship type.
struct definition of the function_decl tree node.
Definition: tree_node.hpp:2759
Source must be executed to satisfy target.
This class contains the base representation for a generic frontend flow step which works on a single ...
Data structure describing a basic block at tree level.
redefinition of map to manage ordered/unordered structures
const tree_nodeConstRef CGetTreeNode(const unsigned int i) const
static std::string GetMangledFunctionName(const function_decl *fd)
Return the mangled function name.
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
CustomOrderedSet< unsigned int > fun_id_to_restartParm
stores the function ids of the functions whose Parm2SSA intra procedural steps have to be invalidated...
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
Standard functor that returns the name of a variable.
tree_nodeRef GetPointerType(const tree_nodeConstRef &ptd, unsigned long long algn=0) const
Function that creates a pointer type if it is not already present, otherwise it returns the one that ...
Classes to describe design flow graph.
redefinition of set to manage ordered/unordered structures
tree_nodeRef GetTreeReindex(const unsigned int i)
Return a tree_reindex wrapping the i-th tree_node.
CustomOrderedSet< unsigned int > fun_id_to_restart
stores the function ids of the functions whose Bit_Value intra procedural steps have to be invalidate...
const Wrefcount< const DesignFlowManager > design_flow_manager
The design flow manager.
Classes specification of the tree_node data structures.
tree_nodeRef GetFunctionType(const tree_nodeConstRef &returnType, const std::vector< tree_nodeConstRef > &argsT) const
Create a function type.
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
This file collects some utility functions and macros.
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.
void ComputeRelationships(DesignFlowStepSet &relationships, const DesignFlowStep::RelationshipType relationship_type) override
Compute the relationships of a step with other steps.
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.
Wrapper of design_flow.
~dead_code_eliminationIPA() override
This file collects some utility functions.
std::vector< tree_nodeRef > list_of_args
args field holds a chain of parm_decl nodes for the arguments.
Definition: tree_node.hpp:2841
dead_code_eliminationIPA(const application_managerRef AM, const DesignFlowManagerConstRef dfm, const ParameterConstRef parameters)
refcount< T > lock() const
Definition: refcount.hpp:212
void ComputeRelationships(DesignFlowStepSet &relationship, const DesignFlowStep::RelationshipType relationship_type) override
Compute the relationships of a step with other steps.
const application_managerRef AppM
The application manager.
Class specification of the tree_reindex support class.
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.
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
tree_nodeRef type
type field holds the data type of the object, when relevant.
Definition: tree_node.hpp:907
this class is used to manage the command-line or XML options.
std::string container_to_string(_InputIt first, _InputIt last, const std::string &separator, bool trim_empty=true)
Definition: utility.hpp:122
Wrapper to call graph.
int debug_level
The debug level.
#define GET_INDEX_CONST_NODE(t)
Definition: tree_node.hpp:363
refcount< const var_pp_functor > var_pp_functorConstRef
static tree_nodeConstRef GetFunctionReturnType(const tree_nodeConstRef &function, bool void_as_null=true)
Return the return type of a function.
bool signature_opt(const tree_managerRef &TM, function_decl *fd, unsigned int function_id, const CustomOrderedSet< unsigned int > &rFunctions)
#define NULL_VERTEX
null vertex definition
Definition: graph.hpp:1305
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.
static const std::string ComputeSignature(const FrontendFlowStepType frontend_flow_step_type, const unsigned int function_id)
Compute the signature of a function frontend flow step.
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:51 for PandA-2024.02 by doxygen 1.8.13