PandA-2024.02
BitValueIPA.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  */
45 // include class header
46 #include "BitValueIPA.hpp"
47 
48 // include from src/
49 #include "Parameter.hpp"
50 
51 // include from src/behavior/
52 #include "behavioral_helper.hpp"
53 #include "call_graph.hpp"
54 #include "call_graph_manager.hpp"
55 #include "function_behavior.hpp"
56 
57 // include from src/design_flow/
58 #include "application_manager.hpp"
59 #include "design_flow_graph.hpp"
60 #include "design_flow_manager.hpp"
61 
62 // include from src/frontend_analysis/
64 
65 #include "behavioral_helper.hpp"
66 #include "custom_map.hpp"
67 #include "custom_set.hpp"
68 #include "dbgPrintHelper.hpp" // for DEBUG_LEVEL_
69 #include "string_manipulation.hpp" // for GET_CLASS
70 #include "tree_basic_block.hpp"
71 #include "tree_helper.hpp"
72 #include "tree_manager.hpp"
73 #include "tree_node.hpp"
74 #include "tree_reindex.hpp"
75 
77 #include <string>
78 #include <utility>
79 
80 BitValueIPA::BitValueIPA(const application_managerRef AM, const DesignFlowManagerConstRef dfm,
81  const ParameterConstRef par)
82  : ApplicationFrontendFlowStep(AM, BIT_VALUE_IPA, dfm, par),
83  BitLatticeManipulator(AM->get_tree_manager(), parameters->get_class_debug_level(GET_CLASS(*this)))
84 {
85  debug_level = parameters->get_class_debug_level(GET_CLASS(*this), DEBUG_LEVEL_NONE);
86 }
87 
88 BitValueIPA::~BitValueIPA() = default;
89 
92 {
94  switch(relationship_type)
95  {
97  {
98  relationships.insert(std::make_pair(BIT_VALUE, ALL_FUNCTIONS));
99  relationships.insert(std::make_pair(CALL_GRAPH_BUILTIN_CALL, ALL_FUNCTIONS));
100  relationships.insert(std::make_pair(COMPUTE_IMPLICIT_CALLS, ALL_FUNCTIONS));
101  relationships.insert(std::make_pair(FUNCTION_ANALYSIS, WHOLE_APPLICATION));
102  relationships.insert(std::make_pair(IR_LOWERING, ALL_FUNCTIONS));
103  relationships.insert(std::make_pair(PARM2SSA, ALL_FUNCTIONS));
104  if(parameters->isOption(OPT_soft_float) && parameters->getOption<bool>(OPT_soft_float))
105  {
106  relationships.insert(std::make_pair(SOFT_FLOAT_CG_EXT, ALL_FUNCTIONS));
107  }
108  relationships.insert(std::make_pair(USE_COUNTING, ALL_FUNCTIONS));
109  relationships.insert(std::make_pair(UN_COMPARISON_LOWERING, ALL_FUNCTIONS));
110  break;
111  }
113  {
114  break;
115  }
117  {
118  break;
119  }
120  default:
121  {
122  THROW_UNREACHABLE("");
123  }
124  }
125  return relationships;
126 }
127 
129  const DesignFlowStep::RelationshipType relationship_type)
130 {
131  if(relationship_type == INVALIDATION_RELATIONSHIP)
132  {
133  for(const auto& i : fun_id_to_restart)
134  {
135  const auto step_signature = FunctionFrontendFlowStep::ComputeSignature(FrontendFlowStepType::BIT_VALUE, i);
136  const auto frontend_step = design_flow_manager.lock()->GetDesignFlowStep(step_signature);
137  THROW_ASSERT(frontend_step != NULL_VERTEX, "step " + step_signature + " is not present");
138  const auto design_flow_graph = design_flow_manager.lock()->CGetDesignFlowGraph();
139  const auto design_flow_step = design_flow_graph->CGetDesignFlowStepInfo(frontend_step)->design_flow_step;
140  relationships.insert(design_flow_step);
141  }
142  fun_id_to_restart.clear();
143  for(const auto& i : fun_id_to_restart_caller)
144  {
145  const auto step_signature = FunctionFrontendFlowStep::ComputeSignature(FrontendFlowStepType::BIT_VALUE, i);
146  const auto frontend_step = design_flow_manager.lock()->GetDesignFlowStep(step_signature);
147  THROW_ASSERT(frontend_step != NULL_VERTEX, "step " + step_signature + " is not present");
148  const auto design_flow_graph = design_flow_manager.lock()->CGetDesignFlowGraph();
149  const auto design_flow_step = design_flow_graph->CGetDesignFlowStepInfo(frontend_step)->design_flow_step;
150  relationships.insert(design_flow_step);
151  }
152  fun_id_to_restart_caller.clear();
153  }
154  ApplicationFrontendFlowStep::ComputeRelationships(relationships, relationship_type);
155 }
156 
158 {
159  std::map<unsigned int, unsigned int> cur_bitvalue_ver;
160  std::map<unsigned int, unsigned int> cur_bb_ver;
161  const auto CGMan = AppM->CGetCallGraphManager();
162  for(const auto i : CGMan->GetReachedBodyFunctions())
163  {
164  const auto FB = AppM->CGetFunctionBehavior(i);
165  cur_bitvalue_ver[i] = FB->GetBitValueVersion();
166  cur_bb_ver[i] = FB->GetBBVersion();
167  }
168  return cur_bb_ver != last_bb_ver || cur_bitvalue_ver != last_bitvalue_ver;
169 }
170 
172 {
173  THROW_ASSERT(parameters->isOption(OPT_bitvalue_ipa) && parameters->getOption<bool>(OPT_bitvalue_ipa),
174  "Bit value IPA should not be executed");
175  if(!AppM->ApplyNewTransformation())
176  {
178  }
179 
181  fun_id_to_restart.clear();
182  fun_id_to_restart_caller.clear();
183 
184  const auto CGMan = AppM->CGetCallGraphManager();
185  const auto cg = CGMan->CGetCallGraph();
186  const auto reached_body_fun_ids = CGMan->GetReachedBodyFunctions();
187  auto root_fun_ids = CGMan->GetRootFunctions();
188  const auto addressed_functions = CGMan->GetAddressedFunctions();
189  root_fun_ids.insert(addressed_functions.begin(), addressed_functions.end());
190 
192  CustomUnorderedSet<vertex> vertex_subset;
193  for(const auto& cvertex : reached_body_fun_ids)
194  {
195  vertex_subset.insert(CGMan->GetVertex(cvertex));
196  }
197  const auto subgraph = CGMan->CGetCallSubGraph(vertex_subset);
198  EdgeIterator e_it, e_it_end;
199  for(boost::tie(e_it, e_it_end) = boost::edges(*subgraph); e_it != e_it_end; ++e_it)
200  {
201  const auto* info = Cget_edge_info<FunctionEdgeInfo, const CallGraph>(*e_it, *subgraph);
202  if(info->indirect_call_points.size())
203  {
205  }
206  }
207 
208  // ---- initialization phase ----
209  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->Initialize data structures");
210  for(const auto& fu_id : reached_body_fun_ids)
211  {
212  const auto fu_name = AppM->CGetFunctionBehavior(fu_id)->CGetBehavioralHelper()->get_function_name();
214  "-->Analyzing function \"" + fu_name + "\": id = " + STR(fu_id));
215  const auto fu_node = TM->CGetTreeReindex(fu_id);
216  const auto fd = GetPointer<function_decl>(GET_CONST_NODE(fu_node));
217  THROW_ASSERT(fd && fd->body, "Node is not a function or it hasn't a body");
218  const auto fu_type = tree_helper::CGetType(fu_node);
219  THROW_ASSERT(GET_CONST_NODE(fu_type)->get_kind() == function_type_K ||
220  GET_CONST_NODE(fu_type)->get_kind() == method_type_K,
221  "node " + STR(fu_id) + " is " + GET_CONST_NODE(fu_type)->get_kind_text());
222  const auto ft = GetPointer<const function_type>(GET_CONST_NODE(fu_type));
224  "is_root = " + STR(root_fun_ids.find(fu_id) != root_fun_ids.end()));
225 
226  // -- process parameters --
227  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->Analyzing parameters");
228  for(const auto& parm_decl_node : fd->list_of_args)
229  {
230  const auto p_decl_id = AppM->getSSAFromParm(fu_id, GET_INDEX_CONST_NODE(parm_decl_node));
231  const auto parmssa = TM->GetTreeNode(p_decl_id);
232  THROW_ASSERT(parmssa->get_kind() == ssa_name_K, "expected an ssa variable");
234  "parm_decl ssa id: " + STR(p_decl_id) + " " + parmssa->ToString());
235  const auto p = GetPointerS<ssa_name>(parmssa);
236  if(!IsHandledByBitvalue(p->type))
237  {
238  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "parameter type is not considered: " + STR(p_decl_id));
239  continue;
240  }
241  THROW_ASSERT(!p->bit_values.empty(),
242  "unexpected condition " + parmssa->ToString() + " for function " + fu_name);
243  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "found bitvalue: " + p->bit_values);
244  best[p_decl_id] = string_to_bitstring(p->bit_values);
246  {
248  signed_var.insert(p_decl_id);
249  }
250  }
251  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--Analyzed parameters");
252 
253  // -- process function returned value --
254  if(!IsHandledByBitvalue(ft->retn) || !tree_helper::IsScalarType(ft->retn))
255  {
257  "<--function return type is not considered: " + STR(ft->retn));
258  continue;
259  }
260  THROW_ASSERT(!fd->bit_values.empty(), "not expected");
261  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "found bitvalue: " + fd->bit_values);
262  best[fu_id] = string_to_bitstring(fd->bit_values);
263 
265  {
267  signed_var.insert(fu_id);
268  }
269  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--Analyzed function \"" + fu_name + "\": id = " + STR(fu_id));
270  }
271  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--Initialized data structures");
272 
273  // ---- propagation phase ----
274  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->Start BitValueIPA propagation");
275  for(const auto& fu_id : reached_body_fun_ids)
276  {
277  const auto fu_name = AppM->CGetFunctionBehavior(fu_id)->CGetBehavioralHelper()->get_function_name();
279  "-->Analyzing function \"" + fu_name + "\": id = " + STR(fu_id));
280 
281  const auto fu_node = TM->CGetTreeReindex(fu_id);
282  const auto fd = GetPointer<const function_decl>(GET_CONST_NODE(fu_node));
283  THROW_ASSERT(fd && fd->body, "Node is not a function or it hasn't a body");
284  const auto fu_type = tree_helper::CGetType(fu_node);
285  THROW_ASSERT(GET_CONST_NODE(fu_type)->get_kind() == function_type_K ||
286  GET_CONST_NODE(fu_type)->get_kind() == method_type_K,
287  "node " + STR(fu_id) + " is " + GET_CONST_NODE(fu_type)->get_kind_text());
288  const auto ft = GetPointer<const function_type>(GET_CONST_NODE(fu_type));
289  const auto fret_type_node = GET_CONST_NODE(ft->retn);
290 
291  if(root_fun_ids.find(fu_id) == root_fun_ids.end())
292  {
293  // --- propagation through return values ---
294  if(best.find(fu_id) != best.end())
295  {
297  "-->Propagating bitvalue of the return value of function " + fu_name);
298 
299  /*
300  * for root functions, don't perform backward propagation from assigned
301  * ssa to returned value, because this could lead to unsafe
302  * optimizations if some external piece of code that was not
303  * synthesized with bambu calls the top function from the bus
304  */
305  // --- backward ----
306 
307  if(!AppM->ApplyNewTransformation())
308  {
311  break;
312  }
313 
314  const auto fu_signed = signed_var.find(fu_id) != signed_var.cend();
316 
317  current.insert(std::make_pair(fu_id, best.at(fu_id)));
318 
319  auto res = create_x_bitstring(1);
320 
321  const auto fu_cgv = CGMan->GetVertex(fu_id);
322  InEdgeIterator ie_it, ie_end;
323  boost::tie(ie_it, ie_end) = boost::in_edges(fu_cgv, *cg);
324  for(; ie_it != ie_end; ie_it++)
325  {
326  const auto caller_id = CGMan->get_function(boost::source(*ie_it, *cg));
327  if(reached_body_fun_ids.find(caller_id) == reached_body_fun_ids.cend())
328  {
329  continue;
330  }
332  "-->examining caller \"" +
333  AppM->CGetFunctionBehavior(caller_id)->CGetBehavioralHelper()->get_function_name() +
334  "\": id = " + STR(caller_id));
335  const auto call_edge_info = cg->CGetFunctionEdgeInfo(*ie_it);
336  for(const auto& i : call_edge_info->direct_call_points)
337  {
338  THROW_ASSERT(i, "unexpected condition");
339  const auto call_node = TM->CGetTreeNode(i);
341  "-->examining direct call point " + call_node->ToString());
342  if(call_node->get_kind() == gimple_assign_K)
343  {
345  const auto ga = GetPointer<const gimple_assign>(call_node);
346  THROW_ASSERT(ga, STR(i) + " is not a gimple assign");
347  if(GET_CONST_NODE(ga->op0)->get_kind() == ssa_name_K)
348  {
349  THROW_ASSERT(GET_CONST_NODE(ga->op1)->get_kind() == call_expr_K ||
350  GET_CONST_NODE(ga->op1)->get_kind() == aggr_init_expr_K,
351  GET_CONST_NODE(ga->op1)->ToString() +
352  " kind = " + GET_CONST_NODE(ga->op1)->get_kind_text());
353  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "assigns ssa_name");
354  const auto s = GetPointerS<const ssa_name>(GET_CONST_NODE(ga->op0));
355  THROW_ASSERT(IsHandledByBitvalue(ga->op0), "ssa is not handled by bitvalue");
356  THROW_ASSERT(
357  tree_helper::IsSignedIntegerType(ga->op0) == fu_signed,
358  "function " +
359  AppM->CGetFunctionBehavior(caller_id)->CGetBehavioralHelper()->get_function_name() +
360  " calls function " + fu_name +
361  " with return type = " + STR(tree_helper::GetFunctionReturnType(fu_node)) +
362  " and assigns the return value to ssa " + STR(s) +
363  " of type = " + STR(tree_helper::CGetType(ga->op0)) + "\ndifferent signedness!");
364  THROW_ASSERT(!s->bit_values.empty(), "unexpected assignment of return value to ssa " + STR(s) +
365  " with id " + STR(s->index) + " and empty bit_values");
366  const auto res_fanout = string_to_bitstring(s->bit_values);
368  "res_fanout from ssa " + STR(s) + " id: " + STR(s->index) +
369  " bitstring: " + bitstring_to_string(res_fanout));
370  THROW_ASSERT(res_fanout.size(), "unexpected condition");
371  res = inf(res, res_fanout, fu_node);
373  "fu_id: " + STR(fu_id) + " bitstring: " + bitstring_to_string(res));
374  auto res_sup = sup(best.at(fu_id), res_fanout, fu_node);
375  auto res_sup_string = bitstring_to_string(res_sup);
376  if(BitLatticeManipulator::isBetter(res_sup_string, s->bit_values))
377  {
379  "" + STR(fu_id) + " " + bitstring_to_string(best.at(fu_id)) +
380  " is better than: " + s->bit_values);
381  fun_id_to_restart_caller.insert(caller_id);
382  }
383  }
384  else
385  {
386  THROW_UNREACHABLE(STR(GET_CONST_NODE(ga->op0)) + ": the assigned value is not an ssa_name: " +
387  GET_CONST_NODE(ga->op0)->get_kind_text());
388  }
389  }
390  else if(call_node->get_kind() == gimple_call_K)
391  {
392  // do nothing
393  }
394  else
395  {
396  THROW_ERROR("unexpected condition " + call_node->ToString());
397  }
398  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--examined call point " + STR(i));
399  }
401  "<--examined caller \"" +
402  AppM->CGetFunctionBehavior(caller_id)->CGetBehavioralHelper()->get_function_name() +
403  "\": id = " + STR(caller_id));
404  }
405 
406  update_current(res, fu_node);
407 
408  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--Backward done");
410  "---After backward id: " + STR(fu_id) +
411  " bitstring: " + STR(bitstring_to_string(best.at(fu_id))));
412 
413  mix();
414  current.clear();
416  "---After mix id: " + STR(fu_id) +
417  " bitstring: " + STR(bitstring_to_string(best.at(fu_id))));
418 
419  AppM->RegisterTransformation(GetName(), fu_node);
420 
422  "<--Propagated bitvalue of the return value of function " + fu_name);
423  }
424  else
425  {
427  "Return value function " + fu_name + " not handled bitvalue");
428  }
429 
430  // --- propagation through parameters ---
431  int args_n = 0;
432  for(const auto& pd : fd->list_of_args)
433  {
434  if(!AppM->ApplyNewTransformation())
435  {
436  break;
437  }
438  const auto pd_id = AppM->getSSAFromParm(fu_id, GET_INDEX_NODE(pd));
439  const auto parmssa = TM->CGetTreeNode(pd_id);
440  THROW_ASSERT(parmssa->get_kind() == ssa_name_K, "expected an ssa variable");
442  "parm_decl ssa id: " + STR(pd_id) + " " + parmssa->ToString());
443 
444  args_n++;
445  if(best.find(pd_id) != best.cend())
446  {
448  "param \"" + STR(pd) + "\" id: " + STR(pd_id) + " not handled by bitvalue");
450  "-->Propagating bitvalue through parameter " + STR(GET_NODE(pd)) + " of function " +
451  fu_name + " parm id: " + STR(pd_id));
452 
453  /*
454  * for root functions, don't perform forward propagation from actual
455  * parameters to formal parameters, because this could lead to unsafe
456  * optimizations if some external piece of code that was not
457  * synthesized with bambu calls the top function from the bus
458  */
459  // --- forward ---
460  {
462  const auto parm_signed = signed_var.find(pd_id) != signed_var.cend();
463 
464  current.insert(std::make_pair(pd_id, best.at(pd_id)));
465 
466  auto res = create_x_bitstring(1);
467 
468  const auto fu_cgv = CGMan->GetVertex(fu_id);
469  InEdgeIterator ie_it, ie_end;
470  boost::tie(ie_it, ie_end) = boost::in_edges(fu_cgv, *cg);
471  for(; ie_it != ie_end; ie_it++)
472  {
473  const auto caller_id = CGMan->get_function(boost::source(*ie_it, *cg));
474  if(reached_body_fun_ids.find(caller_id) == reached_body_fun_ids.cend())
475  {
476  continue;
477  }
478  const auto caller_name =
479  AppM->CGetFunctionBehavior(caller_id)->CGetBehavioralHelper()->get_function_name();
481  "-->examining caller \"" + caller_name + "\": id = " + STR(caller_id));
482  const auto call_edge_info = cg->CGetFunctionEdgeInfo(*ie_it);
483  for(const auto& i : call_edge_info->direct_call_points)
484  {
485  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->examining direct call point " + STR(i));
486  std::deque<bit_lattice> res_tmp;
487  THROW_ASSERT(i, "unexpected condition");
488  const auto call_node = TM->CGetTreeNode(i);
489  if(call_node->get_kind() == gimple_assign_K)
490  {
491  const auto ga = GetPointer<const gimple_assign>(call_node);
492  THROW_ASSERT(GET_CONST_NODE(ga->op1)->get_kind() == call_expr_K ||
493  GET_CONST_NODE(ga->op1)->get_kind() == aggr_init_expr_K,
494  "unexpected pattern");
495 
496  const auto ce = GetPointer<const call_expr>(GET_CONST_NODE(ga->op1));
497  const auto actual_parms = ce->args;
498  THROW_ASSERT(ce->args.size() == fd->list_of_args.size(),
499  "actual parameters: " + STR(ce->args.size()) +
500  " formal parameters: " + STR(fd->list_of_args.size()));
501  const auto ap = std::next(ce->args.cbegin(), args_n - 1);
502  const auto ap_id = GET_INDEX_CONST_NODE(*ap);
503  const auto& ap_node = *ap;
504  const auto ap_kind = GET_CONST_NODE(ap_node)->get_kind();
505  THROW_ASSERT(IsHandledByBitvalue(ap_node), "actual parameter not handled by bitvalue");
506  THROW_ASSERT(tree_helper::IsSignedIntegerType(ap_node) == parm_signed,
507  "function " + caller_name + " calls function " + fu_name + "\nformal param " +
508  STR(pd) + " type = " + STR(tree_helper::CGetType(pd)) + "\nactual param " +
509  STR(ap_node) + " type = " + STR(tree_helper::CGetType(ap_node)) +
510  "\ndifferent signedness!");
511  if(ap_kind == ssa_name_K)
512  {
513  const auto ssa = GetPointerS<const ssa_name>(GET_CONST_NODE(ap_node));
514  res_tmp = ssa->bit_values.empty() ?
516  string_to_bitstring(ssa->bit_values);
518  "actual parameter " + STR(ssa) + " id: " + STR(ssa->index) +
519  " bitstring: " + bitstring_to_string(res_tmp));
520  }
521  else if(ap_kind == integer_cst_K)
522  {
523  const auto cst_val = tree_helper::GetConstValue(ap_node);
525  parm_signed);
527  "actual parameter " + STR(ap_node) +
528  " is a constant value id: " + STR(GET_INDEX_CONST_NODE(ap_node)) +
529  " bitstring: " + bitstring_to_string(res_tmp));
530  }
531  else
532  {
533  THROW_UNREACHABLE("unexpected actual parameter " + STR(ap_node) + " id : " + STR(ap_id) +
534  " of kind: " + tree_node::GetString(ap_kind));
535  }
536  }
537  else if(call_node->get_kind() == gimple_call_K)
538  {
539  const auto gc = GetPointer<const gimple_call>(call_node);
540  const auto actual_parms = gc->args;
541  THROW_ASSERT(gc->args.size() == fd->list_of_args.size(),
542  "actual parameters: " + STR(gc->args.size()) +
543  " formal parameters: " + STR(fd->list_of_args.size()));
544  const auto ap = std::next(gc->args.cbegin(), args_n - 1);
545  const auto ap_id = GET_INDEX_CONST_NODE(*ap);
546  const auto& ap_node = *ap;
547  const auto ap_kind = GET_CONST_NODE(ap_node)->get_kind();
548  THROW_ASSERT(IsHandledByBitvalue(ap_node), "actual parameter not handled by bitvalue");
549  THROW_ASSERT(tree_helper::IsSignedIntegerType(ap_node) == parm_signed,
550  "function " + caller_name + " calls function " + fu_name + "\nformal param " +
551  STR(pd) + " type = " + STR(tree_helper::CGetType(pd)) + "\nactual param " +
552  STR(ap_node) + " type = " + STR(tree_helper::CGetType(ap_node)) +
553  "\ndifferent signedness!");
554  if(ap_kind == ssa_name_K)
555  {
556  const auto ssa = GetPointerS<const ssa_name>(GET_CONST_NODE(ap_node));
557  res_tmp = ssa->bit_values.empty() ?
559  string_to_bitstring(ssa->bit_values);
561  "actual parameter " + STR(ssa) + " id: " + STR(ssa->index) +
562  " bitstring: " + bitstring_to_string(res_tmp));
563  }
564  else if(ap_kind == integer_cst_K)
565  {
566  const auto cst_val = tree_helper::GetConstValue(ap_node);
568  parm_signed);
570  "actual parameter " + STR(ap_node) +
571  " is a constant value id: " + STR(GET_INDEX_CONST_NODE(ap_node)) +
572  " bitstring: " + bitstring_to_string(res_tmp));
573  }
574  else
575  {
576  THROW_UNREACHABLE("unexpected actual parameter " + STR(ap_node) + " id : " + STR(ap_id) +
577  " of kind: " + tree_node::GetString(ap_kind));
578  }
579  }
580  else
581  {
583  "this call point is not in the form (ssa_name = call_expr)\n"
584  "no way to retrieve the actual parameters of the call");
585  THROW_UNREACHABLE("unexpected pattern: function " + fu_name + " is called by " +
586  caller_name + " in operation " + STR(call_node));
587  }
588  res = inf(res, res_tmp, parmssa);
590  "param id: " + STR(pd_id) + " bitstring: " + bitstring_to_string(res));
591  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--examined call point " + STR(i));
592  }
594  "<--examined caller \"" + caller_name + "\": id = " + STR(caller_id));
595  }
596 
597  update_current(res, parmssa);
598 
599  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--Forward done");
601  "---After forward id: " + STR(pd_id) +
602  " bitstring: " + STR(bitstring_to_string(best.at(pd_id))));
603 
604  mix();
605  current.clear();
606  AppM->RegisterTransformation(GetName(), pd);
608  "---After mix id: " + STR(pd_id) +
609  " bitstring: " + STR(bitstring_to_string(best.at(pd_id))));
610  }
612  "<--Propagated bitvalue through parameter " + STR(GET_CONST_NODE(pd)) + " of function " +
613  fu_name + " parm id: " + STR(pd_id));
614  }
615  else
616  {
618  "Parameter " + STR(GET_CONST_NODE(pd)) + " of function " + fu_name +
619  " not handled by bitvalue");
620  }
621  }
622  }
623  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--Analyzed function \"" + fu_name + "\": id = " + STR(fu_id));
624  }
625  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--End BitValueIPA propagation");
626 
627  // ---- update bivalues on IR ----
628  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->Updating IR");
629  for(const auto& b : best)
630  {
631  const auto& tn_id = b.first;
632  const auto new_bitvalue = bitstring_to_string(b.second);
634  "---updating node id: " + STR(tn_id) + " bitstring: " + new_bitvalue);
635  const auto tn = TM->CGetTreeReindex(tn_id);
636  const auto kind = GET_CONST_NODE(tn)->get_kind();
637 
638  std::string null_string = "";
639  std::string* old_bitvalue = &null_string;
640  unsigned long long size = 0u;
641  auto restart_fun_id = 0u;
642  if(kind == function_decl_K)
643  {
644  auto fd = GetPointerS<function_decl>(GET_NODE(tn));
646  "---is a function_decl: " +
647  AppM->CGetFunctionBehavior(fd->index)->CGetBehavioralHelper()->get_function_name() +
648  " id: " + STR(fd->index));
649  THROW_ASSERT(fd->body, "has no body");
650  old_bitvalue = &fd->bit_values;
651  const auto fu_type = tree_helper::CGetType(tn);
652  THROW_ASSERT(GET_CONST_NODE(fu_type)->get_kind() == function_type_K ||
653  GET_CONST_NODE(fu_type)->get_kind() == method_type_K,
654  "node " + STR(tn_id) + " is " + GET_CONST_NODE(fu_type)->get_kind_text());
655  const auto ft = GetPointer<const function_type>(GET_CONST_NODE(fu_type));
656  const auto fret_type_node = GET_CONST_NODE(ft->retn);
657  size = BitLatticeManipulator::Size(fret_type_node);
658  restart_fun_id = fd->index;
659  }
660  else if(kind == ssa_name_K)
661  {
662  auto pd = GetPointerS<ssa_name>(GET_NODE(tn));
663  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "---is a parm_decl: " + STR(pd) + " id: " + STR(pd->index));
664  old_bitvalue = &pd->bit_values;
665  size = BitLatticeManipulator::Size(tn);
666  THROW_ASSERT(pd->var && GET_CONST_NODE(pd->var)->get_kind() == parm_decl_K, "unexpected pattern");
667  const auto pdecl = GetPointerS<const parm_decl>(GET_CONST_NODE(pd->var));
668  restart_fun_id = GET_INDEX_CONST_NODE(pdecl->scpe);
669  }
670  else
671  {
672  THROW_UNREACHABLE("unexpected condition: variable of kind " + tree_node::GetString(kind));
673  }
674 
675  bool restart = false;
676  if(old_bitvalue->empty())
677  {
678  const auto full_bv = bitstring_to_string(create_u_bitstring(size));
679  if(BitLatticeManipulator::isBetter(new_bitvalue, full_bv))
680  {
681  restart = true;
682  }
683  }
684  else if(BitLatticeManipulator::isBetter(new_bitvalue, *old_bitvalue))
685  {
686  restart = true;
687  }
689  "---old bitstring: " + *old_bitvalue + " new bitstring: " + new_bitvalue +
690  " restart = " + (restart ? "YES" : "NO") + " " +
691  AppM->CGetFunctionBehavior(restart_fun_id)->CGetBehavioralHelper()->get_function_name());
692  *old_bitvalue = new_bitvalue;
694  "---updated best id: " + STR(tn_id) + " bitstring: " + *old_bitvalue);
695 
696  if(restart)
697  {
699  "restart function " +
700  AppM->CGetFunctionBehavior(restart_fun_id)->CGetBehavioralHelper()->get_function_name());
701  fun_id_to_restart.insert(restart_fun_id);
702  const auto fu_cgv = CGMan->GetVertex(restart_fun_id);
703  InEdgeIterator ie_it, ie_end;
704  boost::tie(ie_it, ie_end) = boost::in_edges(fu_cgv, *cg);
705  for(; ie_it != ie_end; ie_it++)
706  {
707  const auto caller_id = CGMan->get_function(boost::source(*ie_it, *cg));
708  if(reached_body_fun_ids.find(caller_id) == reached_body_fun_ids.cend())
709  {
710  continue;
711  }
712  const auto call_edge_info = cg->CGetFunctionEdgeInfo(*ie_it);
713  if(!call_edge_info->direct_call_points.empty())
714  {
716  "restart caller " +
717  AppM->CGetFunctionBehavior(caller_id)->CGetBehavioralHelper()->get_function_name());
718  fun_id_to_restart_caller.insert(caller_id);
719  }
720  }
721  }
722  }
724 
726  "Functions to restart: " + STR(fun_id_to_restart.size() + fun_id_to_restart_caller.size()));
728 
729  for(const auto& i : fun_id_to_restart)
730  {
731  const auto FB = AppM->GetFunctionBehavior(i);
732  FB->UpdateBitValueVersion();
733  }
734  for(const auto& i : fun_id_to_restart_caller)
735  {
736  const auto FB = AppM->GetFunctionBehavior(i);
737  FB->UpdateBitValueVersion();
738  }
739 
740  for(const auto& i : CGMan->GetReachedBodyFunctions())
741  {
742  const auto FB = AppM->CGetFunctionBehavior(i);
743  last_bitvalue_ver[i] = FB->GetBitValueVersion();
744  last_bb_ver[i] = FB->GetBBVersion();
745  }
746  return fun_id_to_restart.empty() ? DesignFlowStep_Status::UNCHANGED : DesignFlowStep_Status::SUCCESS;
747 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
BitValueIPA(const application_managerRef AM, const DesignFlowManagerConstRef dfm, const ParameterConstRef parameters)
STD include.
Definition: BitValueIPA.cpp:80
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
std::deque< bit_lattice > create_bitstring_from_constant(integer_cst_t value, unsigned long long len, bool signed_value)
Creates a bitstring from a constant input.
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.
std::deque< bit_lattice > create_x_bitstring(size_t lenght)
Create a bitstring containing bits initialized at <X>
CustomOrderedSet< unsigned int > fun_id_to_restart_caller
Definition: BitValueIPA.hpp:67
#define GET_CLASS(obj)
Macro returning the actual type of an object.
Definition of the class representing a generic C application.
RelationshipType
The relationship type.
Source must be executed to satisfy target.
static bool isBetter(const std::string &a_string, const std::string &b_string)
static std::string GetString(const enum kind k)
Given a kind, return the corresponding string.
Definition: tree_node.cpp:120
boost::graph_traits< graph >::in_edge_iterator InEdgeIterator
in_edge_iterator definition.
Definition: graph.hpp:1310
bool IsHandledByBitvalue(const tree_nodeConstRef &tn) const
Returns true if the type identified by type_id is handled by bitvalue analysis.
#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
~BitValueIPA() override
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
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
static bool IsScalarType(const tree_nodeConstRef &type)
Return true if the treenode is an int, an unsigned, a real or a Boolean data type.
boost::graph_traits< graph >::edge_iterator EdgeIterator
edge_iterator definition.
Definition: graph.hpp:1314
static bool IsSignedIntegerType(const tree_nodeConstRef &type)
Return true if the treenode is of integer type.
CustomSet< unsigned int > signed_var
Set storing the signed ssa.
Definition: bit_lattice.hpp:90
std::string bitstring_to_string(const std::deque< bit_lattice > &bitstring)
Translates a bitstring ( expressed as an std::deque of bit_lattice ) into a string of characters...
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
unsigned edges[4545]
Definition: graph.h:25
std::deque< bit_lattice > inf(const std::deque< bit_lattice > &a, const std::deque< bit_lattice > &b, const unsigned int output_uid) const
Computes the inf between two bitstrings.
DesignFlowStep_Status Exec() override
Execute the step.
std::deque< bit_lattice > create_u_bitstring(size_t lenght)
Creates a bitstring containing bits initialized at <U>
CustomMap< unsigned int, std::deque< bit_lattice > > current
Map of the current bit-values of each variable.
Definition: bit_lattice.hpp:78
bool update_current(std::deque< bit_lattice > &res, const tree_nodeConstRef &tn)
Given a bitstring res, and the id of a tree node ouput_uid, this functions checks if it is necessary ...
Classes to describe design flow graph.
kind
redefinition of set to manage ordered/unordered structures
static unsigned long long size(const tree_managerConstRef tm, unsigned int index)
const Wrefcount< const DesignFlowManager > design_flow_manager
The design flow manager.
void ComputeRelationships(DesignFlowStepSet &relationships, const DesignFlowStep::RelationshipType relationship_type) override
Compute the relationships of a step with other steps.
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
static unsigned long long Size(const tree_nodeConstRef &t)
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.
#define DEBUG_LEVEL_NONE
no debugging print is performed.
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.
Definition: BitValueIPA.cpp:91
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
Wrapper of design_flow.
const tree_managerConstRef TM
Definition: bit_lattice.hpp:71
std::map< unsigned int, unsigned int > last_bitvalue_ver
Definition: BitValueIPA.hpp:69
This file collects some utility functions.
bool mix()
Mixes the content of current and best using the sup operation, storing the result in the best map...
std::deque< bit_lattice > string_to_bitstring(const std::string &s)
inverse of bitstring_to_string
std::deque< bit_lattice > sup(const std::deque< bit_lattice > &a, const std::deque< bit_lattice > &b, const unsigned int output_uid) const
Computes the sup between two bitstrings.
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.
Created on: June 27, 2016.
CustomMap< unsigned int, std::deque< bit_lattice > > best
Map of the best bit-values of each variable.
Definition: bit_lattice.hpp:85
void clear()
Clean up the internal data structures.
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.
this class is used to manage the command-line or XML options.
std::string GetName() const override
Return the name of this design step.
Wrapper to call graph.
static integer_cst_t GetConstValue(const tree_nodeConstRef &tn, bool is_signed=true)
Get value from integer constant.
int debug_level
The debug level.
std::map< unsigned int, unsigned int > last_bb_ver
Definition: BitValueIPA.hpp:71
#define GET_INDEX_CONST_NODE(t)
Definition: tree_node.hpp:363
CustomOrderedSet< unsigned int > fun_id_to_restart
stores the function ids of the functions whose Bit_Value intra procedural steps have to be invalidate...
Definition: BitValueIPA.hpp:66
static tree_nodeConstRef GetFunctionReturnType(const tree_nodeConstRef &function, bool void_as_null=true)
Return the return type of a function.
#define NULL_VERTEX
null vertex definition
Definition: graph.hpp:1305
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.
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
#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