PandA-2024.02
compute_implicit_calls.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  */
70 #include "config_HAVE_PRAGMA_BUILT.hpp"
71 
73 #include "application_manager.hpp"
74 #include "call_graph.hpp"
75 #include "call_graph_manager.hpp"
76 #include "function_behavior.hpp"
77 
79 #include "Parameter.hpp"
80 #include "module_interface.hpp"
81 
83 #include "behavioral_helper.hpp"
84 #include "dbgPrintHelper.hpp" // for DEBUG_LEVEL_
85 #include "ext_tree_node.hpp"
86 #include "op_graph.hpp"
87 #include "string_manipulation.hpp" // for GET_CLASS
88 #include "tree_basic_block.hpp"
89 #include "tree_helper.hpp"
90 #include "tree_manager.hpp"
91 #include "tree_manipulation.hpp"
92 #include "tree_node.hpp"
93 #include "tree_reindex.hpp"
94 
96  unsigned int _function_id,
97  const DesignFlowManagerConstRef _design_flow_manager)
98  : FunctionFrontendFlowStep(_AppM, _function_id, COMPUTE_IMPLICIT_CALLS, _design_flow_manager, _parameters),
99  TM(_AppM->get_tree_manager()),
100  update_bb_ver(false)
101 {
102  debug_level = parameters->get_class_debug_level(GET_CLASS(*this), DEBUG_LEVEL_NONE);
103 }
104 
106 
109 {
111  switch(relationship_type)
112  {
114  {
115  relationships.insert(std::make_pair(CHECK_SYSTEM_TYPE, SAME_FUNCTION));
116  relationships.insert(std::make_pair(IR_LOWERING, SAME_FUNCTION));
117  relationships.insert(std::make_pair(FUNCTION_ANALYSIS, WHOLE_APPLICATION));
118  relationships.insert(std::make_pair(FIX_STRUCTS_PASSED_BY_VALUE, SAME_FUNCTION));
119  relationships.insert(std::make_pair(USE_COUNTING, SAME_FUNCTION));
120  break;
121  }
123  {
124  break;
125  }
127  {
128  break;
129  }
130  default:
131  {
132  THROW_UNREACHABLE("");
133  }
134  }
135  return relationships;
136 }
137 
139 {
141  const auto fd = GetPointer<function_decl>(node);
142  if(!fd || !fd->body)
143  {
144  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Node is not a function or it hasn't a body");
146  }
147  bool changed = false;
148  std::list<std::pair<tree_nodeRef, unsigned int>> to_be_lowered_memset;
149 
151  const auto tree_man = tree_manipulationRef(new tree_manipulation(TM, parameters, AppM));
152 
153  unsigned int max_loop_id = 0;
154 
155  const auto sl = GetPointer<statement_list>(GET_NODE(fd->body));
156  THROW_ASSERT(sl, "Body is not a statement_list");
157  for(const auto& bb : sl->list_of_bloc)
158  {
159  if(bb.second->number == BB_ENTRY || bb.second->number == BB_EXIT)
160  {
161  continue;
162  }
163  max_loop_id = std::max(max_loop_id, bb.second->loop_id);
164  // Statement list may be modified during the scan, thus it is necessary to iterate over a constant copy of it
165  const std::list<tree_nodeRef> const_sl = bb.second->CGetStmtList();
166  for(const auto& stmt : const_sl)
167  {
168  const auto tn = GET_NODE(stmt);
169  if(tn->get_kind() == gimple_assign_K)
170  {
171  const auto gm = GetPointer<gimple_assign>(tn);
172  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Analyzing node " + tn->ToString());
173 
175  const auto op0 = GET_NODE(gm->op0);
176  const auto op1 = GET_NODE(gm->op1);
177  const auto op0_type = tree_helper::CGetType(op0);
178  const auto op1_type = tree_helper::CGetType(op1);
179 
180  bool is_a_vector_bitfield = false;
181  if(op1->get_kind() == bit_field_ref_K)
182  {
183  const auto bfr = GetPointer<bit_field_ref>(op1);
184  if(tree_helper::IsVectorType(bfr->op0))
185  {
186  is_a_vector_bitfield = true;
187  }
188  }
189 
190  bool load_candidate = (op1->get_kind() == bit_field_ref_K && !is_a_vector_bitfield) ||
191  op1->get_kind() == component_ref_K || op1->get_kind() == indirect_ref_K ||
192  op1->get_kind() == misaligned_indirect_ref_K || op1->get_kind() == mem_ref_K ||
193  op1->get_kind() == array_ref_K || op1->get_kind() == target_mem_ref_K ||
194  op1->get_kind() == target_mem_ref461_K;
195  if(op1->get_kind() == realpart_expr_K || op1->get_kind() == imagpart_expr_K)
196  {
197  const auto code1 = GET_NODE(GetPointer<unary_expr>(op1)->op)->get_kind();
198  if((code1 == bit_field_ref_K && !is_a_vector_bitfield) || code1 == component_ref_K ||
199  code1 == indirect_ref_K || code1 == bit_field_ref_K || code1 == misaligned_indirect_ref_K ||
200  code1 == mem_ref_K || code1 == array_ref_K || code1 == target_mem_ref_K ||
201  code1 == target_mem_ref461_K)
202  {
203  load_candidate = true;
204  }
205  if(code1 == var_decl_K)
206  {
207  load_candidate = true;
208  }
209  }
210  bool store_candidate = op0->get_kind() == bit_field_ref_K || op0->get_kind() == component_ref_K ||
211  op0->get_kind() == indirect_ref_K || op0->get_kind() == misaligned_indirect_ref_K ||
212  op0->get_kind() == mem_ref_K || op0->get_kind() == array_ref_K ||
213  op0->get_kind() == target_mem_ref_K || op0->get_kind() == target_mem_ref461_K;
214  if(op0->get_kind() == realpart_expr_K || op0->get_kind() == imagpart_expr_K)
215  {
216  const auto code0 = GET_NODE(GetPointer<unary_expr>(op0)->op)->get_kind();
217  if(code0 == component_ref_K || code0 == indirect_ref_K || code0 == bit_field_ref_K ||
218  code0 == misaligned_indirect_ref_K || code0 == mem_ref_K || code0 == array_ref_K ||
219  code0 == target_mem_ref_K || code0 == target_mem_ref461_K)
220  {
221  store_candidate = true;
222  }
223  if(code0 == var_decl_K)
224  {
225  store_candidate = true;
226  }
227  }
228  if(!gm->clobber && !gm->init_assignment && op0_type && op1_type && op1->get_kind() != insertvalue_expr_K &&
229  op1->get_kind() != extractvalue_expr_K &&
230  ((GET_CONST_NODE(op0_type)->get_kind() == record_type_K &&
231  GET_CONST_NODE(op1_type)->get_kind() == record_type_K && op1->get_kind() != view_convert_expr_K) ||
232  (GET_CONST_NODE(op0_type)->get_kind() == union_type_K &&
233  GET_CONST_NODE(op1_type)->get_kind() == union_type_K && op1->get_kind() != view_convert_expr_K) ||
234  (GET_CONST_NODE(op0_type)->get_kind() == array_type_K) || (store_candidate && load_candidate)))
235  {
236  changed = true;
237  const auto mr = GetPointer<mem_ref>(op0);
238  THROW_ASSERT(mr, "unexpected condition " + gm->ToString());
240  const auto dst_type = tree_helper::CGetType(mr->op0);
241  const auto dst_ptr_t = GetPointer<const pointer_type>(GET_CONST_NODE(dst_type));
242  THROW_ASSERT(dst_ptr_t, "unexpected condition");
243  const auto dst_size = tree_helper::Size(dst_ptr_t->ptd);
244  if(dst_size)
245  {
246  if(op1->get_kind() == constructor_K && GetPointer<constructor>(op1) &&
247  GetPointer<constructor>(op1)->list_of_idx_valu.size() == 0)
248  {
249  const auto var = tree_helper::GetBaseVariable(mr->op0);
250  bool do_lowering = var != nullptr;
251  if(do_lowering)
252  {
253  const auto type_node = tree_helper::CGetType(var);
254  do_lowering = type_node->get_kind() == array_type_K;
255  if(do_lowering)
256  {
257  const auto element_type = tree_helper::CGetElements(type_node);
258  const auto element_type_kind = GET_CONST_NODE(element_type)->get_kind();
259  if(!(element_type_kind == boolean_type_K || element_type_kind == CharType_K ||
260  element_type_kind == enumeral_type_K || element_type_kind == integer_type_K ||
261  element_type_kind == pointer_type_K or element_type_kind == record_type_K))
262  {
263  do_lowering = false;
264  THROW_ASSERT(
265  element_type_kind == array_type_K || element_type_kind == nullptr_type_K ||
266  element_type_kind == type_pack_expansion_K || element_type_kind == real_type_K ||
267  element_type_kind == complex_type_K or element_type_kind == function_type_K ||
268  element_type_kind == lang_type_K || element_type_kind == method_type_K ||
269  element_type_kind == offset_type_K || element_type_kind == qual_union_type_K or
270  element_type_kind == record_type_K || element_type_kind == reference_type_K ||
271  element_type_kind == set_type_K || element_type_kind == template_type_parm_K ||
272  element_type_kind == typename_type_K or element_type_kind == union_type_K ||
273  element_type_kind == vector_type_K || element_type_kind == void_type_K,
274  tree_node::GetString(element_type_kind));
275  }
276  }
277  }
278  if(do_lowering)
279  {
280  to_be_lowered_memset.push_front(std::make_pair(stmt, bb.second->number));
281  }
282  else
283  {
284  THROW_ASSERT(GetPointerS<const function_decl>(GET_CONST_NODE(TM->GetFunction(MEMSET)))->body,
285  "inconsistent behavioral helper");
286  replace_with_memset(stmt, sl, tree_man);
287  update_bb_ver = true;
288  }
289  }
290  else
291  {
292  THROW_ASSERT(GetPointerS<const function_decl>(GET_CONST_NODE(TM->GetFunction(MEMCPY)))->body,
293  "inconsistent behavioral helper");
294  replace_with_memcpy(stmt, sl, tree_man);
295  update_bb_ver = true;
296  }
297  }
298  else
299  {
300  bb.second->RemoveStmt(stmt, AppM);
301  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Empty struct assignement removed");
302  }
303  }
304  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Analyzed node " + tn->ToString());
305  }
306  }
307  }
308 
310  for(const auto& stmt_bb_pair : to_be_lowered_memset)
311  {
313  "-->Transforming (" + STR(stmt_bb_pair.first->index) + ") " + STR(stmt_bb_pair.first));
314  const auto BB1_block = sl->list_of_bloc.at(stmt_bb_pair.second);
315 
317  const auto BBN1_block = blocRef(new bloc((sl->list_of_bloc.rbegin())->first + 1));
318  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Created BB" + STR(BBN1_block->number));
319  sl->add_bloc(BBN1_block);
320 
321  ++max_loop_id;
322  BBN1_block->loop_id = max_loop_id;
323  BBN1_block->schedule = BB1_block->schedule;
324  BBN1_block->SetSSAUsesComputed();
325 
327  BBN1_block->add_pred(BB1_block->number);
328  BBN1_block->add_pred(BBN1_block->number);
329  BBN1_block->add_succ(BBN1_block->number);
330  BBN1_block->true_edge = BBN1_block->number;
331 
333  const auto BBN2_block = blocRef(new bloc((sl->list_of_bloc.rbegin())->first + 1));
334  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Created BB" + STR(BBN2_block->number));
335  sl->add_bloc(BBN2_block);
336 
337  BBN2_block->loop_id = BB1_block->loop_id;
338  BBN2_block->schedule = BB1_block->schedule;
339  BBN2_block->SetSSAUsesComputed();
340 
342  BBN2_block->add_pred(BBN1_block->number);
344  BBN2_block->list_of_succ = BB1_block->list_of_succ;
346  BBN2_block->true_edge = BB1_block->true_edge;
347  BBN2_block->false_edge = BB1_block->false_edge;
348  BB1_block->true_edge = 0;
349  BB1_block->false_edge = 0;
350  BB1_block->list_of_succ.clear();
351  BB1_block->add_succ(BBN1_block->number);
352 
354  BBN1_block->add_succ(BBN2_block->number);
355  BBN1_block->false_edge = BBN2_block->number;
356 
358  for(const auto& succ : BBN2_block->list_of_succ)
359  {
360  const auto succ_block = sl->list_of_bloc.at(succ);
361  succ_block->list_of_pred.erase(
362  std::find(succ_block->list_of_pred.begin(), succ_block->list_of_pred.end(), BB1_block->number));
363  succ_block->add_pred(BBN2_block->number);
365  for(const auto& phi : succ_block->CGetPhiList())
366  {
367  auto gp = GetPointerS<gimple_phi>(GET_NODE(phi));
368  for(const auto& def_edge : gp->CGetDefEdgesList())
369  {
370  if(def_edge.second == BB1_block->number)
371  {
372  gp->ReplaceDefEdge(TM, def_edge, gimple_phi::DefEdge(def_edge.first, BBN2_block->number));
373  }
374  }
375  }
376  }
377 
379  const auto ga = GetPointerS<gimple_assign>(GET_NODE(stmt_bb_pair.first));
380  const auto mr = GetPointerS<mem_ref>(GET_NODE(ga->op0));
381  const auto var = TM->CGetTreeReindex(tree_helper::GetBaseVariable(mr->op0)->index);
382  auto init_var = mr->op0;
383  const auto srcp_default = ga->include_name + ":" + STR(ga->line_number) + ":" + STR(ga->column_number);
384  auto type_node1 = tree_helper::CGetType(var);
385  const auto algn = GetPointerS<const type_node>(GET_CONST_NODE(type_node1))->algn;
386  THROW_ASSERT(GET_CONST_NODE(type_node1)->get_kind() == array_type_K, "unexpected condition");
387  while(GET_CONST_NODE(type_node1)->get_kind() == array_type_K)
388  {
389  type_node1 = tree_helper::CGetElements(type_node1);
390  }
391  const auto offset_type = tree_man->GetSizeType();
392  const auto pt = tree_man->GetPointerType(type_node1, algn);
393 
395  const auto nop_init_var = tree_man->create_unary_operation(pt, init_var, srcp_default, nop_expr_K);
396  const auto nop_init_var_ga =
397  tree_man->CreateGimpleAssign(pt, tree_nodeRef(), tree_nodeRef(), nop_init_var, function_id, srcp_default);
398  init_var = GetPointerS<gimple_assign>(GET_NODE(nop_init_var_ga))->op0;
400  "---Created cast statement " + GET_NODE(nop_init_var_ga)->ToString());
401 
403  tree_nodeRef new_induction_var;
405  std::vector<std::pair<tree_nodeRef, unsigned int>> list_of_def_edge;
406  list_of_def_edge.push_back(std::make_pair(init_var, BB1_block->number));
407  const auto phi = tree_man->create_phi_node(new_induction_var, list_of_def_edge, function_id);
408  const auto gp = GetPointerS<gimple_phi>(GET_NODE(phi));
409  const auto phi_res_use_set = PointToSolutionRef(new PointToSolution());
410  phi_res_use_set->Add(var);
411  GetPointerS<ssa_name>(GET_NODE(gp->res))->use_set = phi_res_use_set;
412  BBN1_block->AddPhi(phi);
413 
415  const auto dst_type = tree_helper::CGetType(mr->op0);
416  const auto dst_ptr_t = GetPointer<const pointer_type>(GET_CONST_NODE(dst_type));
417  THROW_ASSERT(dst_ptr_t, "unexpected condition");
418  const auto dst_size = tree_helper::Size(dst_ptr_t->ptd);
419  THROW_ASSERT(dst_size % 8 == 0, "unexpected condition");
420  const auto copy_byte_size = dst_size / 8;
421  const auto copy_byte_size_node =
422  TM->CreateUniqueIntegerCst(static_cast<long long int>(copy_byte_size), offset_type);
423  const auto pp =
424  tree_man->create_binary_operation(pt, init_var, copy_byte_size_node, srcp_default, pointer_plus_expr_K);
425  const auto pp_ga =
426  tree_man->CreateGimpleAssign(pt, tree_nodeRef(), tree_nodeRef(), pp, function_id, srcp_default);
427  GetPointerS<gimple_assign>(GET_NODE(pp_ga))->temporary_address = true;
428  const auto vd_limit = GetPointerS<gimple_assign>(GET_NODE(pp_ga))->op0;
429  const auto vd_limit_use_set = PointToSolutionRef(new PointToSolution());
430  vd_limit_use_set->Add(var);
431  GetPointerS<ssa_name>(GET_NODE(vd_limit))->use_set = vd_limit_use_set;
432  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Create statement " + GET_NODE(pp_ga)->ToString());
433 
434  const auto size_node =
435  TM->CreateUniqueIntegerCst(static_cast<long long int>(tree_helper::Size(type_node1) / 8), offset_type);
436  const auto pp_ind = tree_man->create_binary_operation(pt, gp->res, size_node, srcp_default, pointer_plus_expr_K);
437  const auto pp_ga_ind =
438  tree_man->CreateGimpleAssign(pt, tree_nodeRef(), tree_nodeRef(), pp_ind, function_id, srcp_default);
439  GetPointerS<gimple_assign>(GET_NODE(pp_ga_ind))->temporary_address = true;
440  const auto vd_ind = GetPointerS<gimple_assign>(GET_NODE(pp_ga_ind))->op0;
441  const auto vd_ind_use_set = PointToSolutionRef(new PointToSolution());
442  vd_ind_use_set->Add(var);
443  GetPointerS<ssa_name>(GET_NODE(vd_ind))->use_set = vd_ind_use_set;
444  gp->AddDefEdge(TM, gimple_phi::DefEdge(vd_ind, BBN1_block->number));
445  BBN1_block->PushBack(pp_ga_ind, AppM);
446  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Create statement " + GET_NODE(pp_ga_ind)->ToString());
447 
449  const auto boolean_type = tree_man->GetBooleanType();
450  const auto comparison =
451  tree_man->create_binary_operation(boolean_type, vd_ind, vd_limit, srcp_default, ne_expr_K);
452  const auto comp_ga = tree_man->CreateGimpleAssign(boolean_type, TM->CreateUniqueIntegerCst(0, type_node1),
453  TM->CreateUniqueIntegerCst(1, type_node1), comparison,
454  function_id, srcp_default);
455  BBN1_block->PushBack(comp_ga, AppM);
456  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Create comparison " + STR(comp_ga));
457 
459  const auto comp_res = GetPointerS<gimple_assign>(GET_NODE(comp_ga))->op0;
460  const auto gc = tree_man->create_gimple_cond(comp_res, function_id, srcp_default);
461  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Create branch condition " + STR(gc));
462 
464  const auto zero_offset = TM->CreateUniqueIntegerCst(0, pt);
465  const auto new_mem_ref =
466  tree_man->create_binary_operation(type_node1, gp->res, zero_offset, srcp_default, mem_ref_K);
467  const auto zero_value = TM->CreateUniqueIntegerCst(0, type_node1);
468  TM->ReplaceTreeNode(stmt_bb_pair.first, ga->op0, new_mem_ref);
469  TM->ReplaceTreeNode(stmt_bb_pair.first, ga->op1, zero_value);
470 
471  const auto list_of_stmt = BB1_block->CGetStmtList();
472  bool found_memset_statement = false;
474  for(auto statement = list_of_stmt.begin(); statement != list_of_stmt.end(); statement++)
475  {
476  if(GET_INDEX_NODE(*statement) == GET_INDEX_CONST_NODE(stmt_bb_pair.first))
477  {
479  found_memset_statement = true;
480  const auto temp_statement = *statement;
482  auto tmp_it = statement;
483  ++tmp_it;
485  BB1_block->RemoveStmt(temp_statement, AppM);
486  BBN1_block->PushBack(temp_statement, AppM);
488  --tmp_it;
489  statement = tmp_it;
490  }
491  else if(found_memset_statement)
492  {
494  const auto temp_statement = *statement;
496  auto tmp_it = statement;
497  ++tmp_it;
499  BB1_block->RemoveStmt(temp_statement, AppM);
500  BBN2_block->PushBack(temp_statement, AppM);
502  --tmp_it;
503  statement = tmp_it;
504  }
505  }
506  THROW_ASSERT(found_memset_statement, "unexpected condition");
507  BB1_block->PushBack(nop_init_var_ga, AppM);
508  BB1_block->PushBack(pp_ga, AppM);
509  BBN1_block->PushBack(gc, AppM);
510  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Transformed " + STR(stmt_bb_pair.first));
511  }
512  if(debug_level >= DEBUG_LEVEL_PEDANTIC && parameters->getOption<bool>(OPT_print_dot) &&
513  (!parameters->IsParameter("print-dot-FF") || parameters->GetParameter<unsigned int>("print-dot-FF")))
514  {
515  AppM->CGetCallGraphManager()->CGetCallGraph()->WriteDot("compute_implicit_calls" + GetSignature() + ".dot");
516  }
517  if(update_bb_ver)
518  {
519  AppM->GetFunctionBehavior(function_id)->UpdateBBVersion();
520  }
522 }
523 
525  tree_manipulationRef tree_man) const
526 {
527  const auto ga = GetPointer<const gimple_assign>(GET_CONST_NODE(stmt));
528  const auto lhs_node = GET_CONST_NODE(ga->op0);
529  THROW_ASSERT(
530  lhs_node->get_kind() == mem_ref_K,
531  "unexpected condition: " + AppM->CGetFunctionBehavior(function_id)->CGetBehavioralHelper()->get_function_name() +
532  " calls function " + MEMCPY + " in operation " + ga->ToString() + " but lhs " + lhs_node->ToString() +
533  " is not a mem_ref: it's a " + lhs_node->get_kind_text());
534  const auto mr_lhs = GetPointer<const mem_ref>(lhs_node);
535  THROW_ASSERT(GetPointer<const ssa_name>(GET_CONST_NODE(mr_lhs->op0)), "");
536  THROW_ASSERT(
537  GET_CONST_NODE(mr_lhs->op1)->get_kind() == integer_cst_K && tree_helper::GetConstValue(mr_lhs->op1) == 0, "");
538  const auto rhs_node = GET_CONST_NODE(ga->op1);
539  const auto rhs_kind = rhs_node->get_kind();
540 
541  const auto s = GetPointer<const srcp>(GET_CONST_NODE(stmt));
542  const std::string current_srcp =
543  s ? (s->include_name + ":" + STR(s->line_number) + ":" + STR(s->column_number)) : "";
544 
545  unsigned long int copy_byte_size = 0;
546  // args to be filled before the creation of the gimple call
547  // dst is always the ssa on the rhs
548  std::vector<tree_nodeRef> args = {mr_lhs->op0};
549 
550  THROW_ASSERT(
551  rhs_kind == mem_ref_K || rhs_kind == parm_decl_K || rhs_kind == string_cst_K,
552  "unexpected condition: " + AppM->CGetFunctionBehavior(function_id)->CGetBehavioralHelper()->get_function_name() +
553  " calls function " + MEMCPY + " in operation " + ga->ToString() + " but rhs " + rhs_node->ToString() +
554  " is not a mem_ref: it's a " + rhs_node->get_kind_text());
555  if(rhs_kind == mem_ref_K)
556  {
557  const auto mr_rhs = GetPointer<const mem_ref>(rhs_node);
558  THROW_ASSERT(GetPointer<const ssa_name>(GET_CONST_NODE(mr_rhs->op0)), "");
559  THROW_ASSERT(
560  GET_CONST_NODE(mr_rhs->op1)->get_kind() == integer_cst_K && tree_helper::GetConstValue(mr_rhs->op1) == 0, "");
561 
562  // src
563  args.push_back(mr_rhs->op0);
564 
565  // compute the size in bytes of the copied memory
566  const auto dst_type = tree_helper::CGetType(mr_lhs->op0);
567  const auto src_type = tree_helper::CGetType(mr_rhs->op0);
568  const auto dst_ptr_t = GetPointer<const pointer_type>(GET_CONST_NODE(dst_type));
569  const auto src_ptr_t = GetPointer<const pointer_type>(GET_CONST_NODE(src_type));
570  unsigned long long dst_size;
571  if(dst_ptr_t)
572  {
573  dst_size = tree_helper::Size(dst_ptr_t->ptd);
574  }
575  else
576  {
577  const auto dst_rptr_t = GetPointer<const reference_type>(GET_CONST_NODE(dst_type));
578  dst_size = tree_helper::Size(dst_rptr_t->refd);
579  }
580  unsigned long long src_size;
581  if(src_ptr_t)
582  {
583  src_size = tree_helper::Size(src_ptr_t->ptd);
584  }
585  else
586  {
587  const auto src_rptr_t = GetPointer<const reference_type>(GET_CONST_NODE(src_type));
588  src_size = tree_helper::Size(src_rptr_t->refd);
589  }
590  if(src_size != dst_size)
591  {
593  "---WARNING: src_size = " + STR(src_size) + "; dst_size = " + STR(dst_size));
594  }
595  THROW_ASSERT(src_size % 8U == 0, "");
596  copy_byte_size = src_size / 8U;
597  }
598  else if(rhs_kind == string_cst_K)
599  {
600  // compute src param
601  const auto memcpy_src_ga = tree_man->CreateGimpleAssignAddrExpr(rhs_node, function_id, current_srcp);
602  // push the new gimple_assign with lhs = addr_expr(param_decl) before the call
603  THROW_ASSERT(not sl->list_of_bloc.empty(), "");
604  THROW_ASSERT(sl->list_of_bloc.find(ga->bb_index) != sl->list_of_bloc.end(), "");
605  const auto block = sl->list_of_bloc.at(ga->bb_index);
606  block->PushBefore(memcpy_src_ga, stmt, AppM);
607  // push back src param
608  const auto new_ga = GetPointer<const gimple_assign>(GET_CONST_NODE(memcpy_src_ga));
609  args.push_back(new_ga->op0);
610 
611  // compute the size in bytes of the copied memory
612  const auto dst_type = tree_helper::CGetType(mr_lhs->op0);
613  const auto dst_ptr_t = GetPointer<const pointer_type>(GET_CONST_NODE(dst_type));
614  THROW_ASSERT(dst_ptr_t, "");
615  const auto dst_bitsize = tree_helper::Size(dst_ptr_t->ptd);
616  THROW_ASSERT(dst_bitsize % 8U == 0, "");
617  const auto dst_size = dst_bitsize / 8U;
618  const auto sc = GetPointer<const string_cst>(rhs_node);
619  const auto src_strlen = sc->strg.length();
620  if((src_strlen + 1) != dst_size)
621  {
623  "---WARNING: src_strlen = " + STR(src_strlen) + "; dst_size = " + STR(dst_size));
624  }
625  copy_byte_size = src_strlen;
626  }
627  else // rhs_kind == parm_decl_K
628  {
629  // compute src param
630  const auto memcpy_src_ga = tree_man->CreateGimpleAssignAddrExpr(rhs_node, function_id, current_srcp);
631  // push the new gimple_assign with lhs = addr_expr(param_decl) before the call
632  THROW_ASSERT(!sl->list_of_bloc.empty(), "");
633  THROW_ASSERT(sl->list_of_bloc.find(ga->bb_index) != sl->list_of_bloc.end(), "");
634  const auto block = sl->list_of_bloc.at(ga->bb_index);
635  block->PushBefore(memcpy_src_ga, stmt, AppM);
636  // push back src param
637  const auto new_ga = GetPointer<const gimple_assign>(GET_CONST_NODE(memcpy_src_ga));
638  args.push_back(new_ga->op0);
639 
640  // compute the size in bytes of the copied memory
641  const auto dst_type = tree_helper::CGetType(mr_lhs->op0);
642  const auto src_type = GET_CONST_NODE(tree_man->GetPointerType(tree_helper::CGetType(rhs_node), 8));
643  const auto dst_ptr_t = GetPointer<const pointer_type>(GET_CONST_NODE(dst_type));
644  const auto src_ptr_t = GetPointer<const pointer_type>(src_type);
645  THROW_ASSERT(dst_ptr_t, "");
646  THROW_ASSERT(src_ptr_t, "");
647  const auto dst_size = tree_helper::Size(dst_ptr_t->ptd);
648  const auto src_size = tree_helper::Size(src_ptr_t->ptd);
649  if(src_size != dst_size)
650  {
652  "---WARNING: src_size = " + STR(src_size) + "; dst_size = " + STR(dst_size));
653  }
654  THROW_ASSERT(src_size % 8 == 0, "");
655  copy_byte_size = src_size / 8;
656  }
658 
659  const auto memcpy_fu_node = TM->GetFunction(MEMCPY);
660  // add size to arguments
661  const auto formal_type_node = tree_helper::GetFormalIth(memcpy_fu_node, 2);
662  args.push_back(TM->CreateUniqueIntegerCst(static_cast<long long>(copy_byte_size), formal_type_node));
663  // create the new gimple call
664  const auto new_gimple_call = tree_man->create_gimple_call(memcpy_fu_node, args, function_id, current_srcp);
665  // replace the gimple_assign with the new gimple_call
666  THROW_ASSERT(!sl->list_of_bloc.empty(), "");
667  THROW_ASSERT(sl->list_of_bloc.find(ga->bb_index) != sl->list_of_bloc.end(), "");
668  const auto block = sl->list_of_bloc.at(ga->bb_index);
669  block->Replace(stmt, new_gimple_call, true, AppM);
670 
672  "---Replaced hidden call " + STR(ga) + " with call " + STR(new_gimple_call) +
673  " id: " + STR(new_gimple_call->index));
674 }
675 
677  tree_manipulationRef tree_man) const
678 {
679  const auto ga = GetPointer<const gimple_assign>(GET_CONST_NODE(stmt));
680  const auto lhs_node = GET_CONST_NODE(ga->op0);
681  THROW_ASSERT(
682  lhs_node->get_kind() == mem_ref_K,
683  "unexpected condition: " + AppM->CGetFunctionBehavior(function_id)->CGetBehavioralHelper()->get_function_name() +
684  " calls function " + MEMSET + " in operation " + ga->ToString() + " but lhs " + lhs_node->ToString() +
685  " is not a mem_ref: it's a " + lhs_node->get_kind_text());
686  const auto mr_lhs = GetPointer<const mem_ref>(lhs_node);
687  THROW_ASSERT(GetPointer<const ssa_name>(GET_CONST_NODE(mr_lhs->op0)), "");
688  THROW_ASSERT(
689  GET_CONST_NODE(mr_lhs->op1)->get_kind() == integer_cst_K && tree_helper::GetConstValue(mr_lhs->op1) == 0, "");
690 
691  const auto s = GetPointer<const srcp>(GET_CONST_NODE(stmt));
692  const auto current_srcp = s ? (s->include_name + ":" + STR(s->line_number) + ":" + STR(s->column_number)) : "";
693 
694  unsigned long int copy_byte_size = 0U;
695  // args to be filled before the creation of the gimple call
696  // dst is always the ssa on the rhs
697  std::vector<tree_nodeRef> args = {mr_lhs->op0};
698 
699  THROW_ASSERT(GetPointer<const constructor>(GET_CONST_NODE(ga->op1))->list_of_idx_valu.empty(), "");
700  const auto memset_fu_node = TM->GetFunction(MEMSET);
701 
702  // create the second argument of memset
703  const auto memset_val_formal_type = tree_helper::GetFormalIth(memset_fu_node, 1);
704  args.push_back(TM->CreateUniqueIntegerCst(0, memset_val_formal_type));
705 
706  // compute the size of memory to be set with memset
707  const auto dst_type = tree_helper::CGetType(mr_lhs->op0);
708  const auto dst_ptr_t = GetPointer<const pointer_type>(GET_CONST_NODE(dst_type));
709  THROW_ASSERT(dst_ptr_t, "");
710  const auto dst_size = tree_helper::Size(dst_ptr_t->ptd);
711  THROW_ASSERT(dst_size % 8U == 0, "");
712  copy_byte_size = dst_size / 8U;
714 
715  // add size to arguments
716  const auto size_formal_type = tree_helper::GetFormalIth(memset_fu_node, 2);
717  args.push_back(TM->CreateUniqueIntegerCst(static_cast<long long>(copy_byte_size), size_formal_type));
718  // create the new gimple call
719  const auto new_gimple_call = tree_man->create_gimple_call(memset_fu_node, args, function_id, current_srcp);
720  // replace the gimple_assign with the new gimple_call
721  THROW_ASSERT(!sl->list_of_bloc.empty(), "");
722  THROW_ASSERT(sl->list_of_bloc.find(ga->bb_index) != sl->list_of_bloc.end(), "");
723  const auto block = sl->list_of_bloc.at(ga->bb_index);
724  block->Replace(stmt, new_gimple_call, true, AppM);
725 
727  "<--Replaced hidden call " + STR(ga) + " with call " + STR(new_gimple_call) +
728  " id: " + STR(new_gimple_call->index));
729 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
This struct specifies a point-to solution.
Definition: tree_node.hpp:1001
static tree_nodeConstRef GetFormalIth(const tree_nodeConstRef &obj, unsigned int parm_index)
Return the type of the ith formal parameter in case index_obj is a call_expr.
refcount< PointToSolution > PointToSolutionRef
Definition: tree_node.hpp:1073
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
This struct specifies the field bloc (basic block).
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
#define MEMCPY
constant string identifying the operation performed when two objects are memcopied.
Definition: op_graph.hpp:310
File containing functions and utilities to support the printing of debug messagges.
#define PRINT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
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.
#define DEBUG_LEVEL_PEDANTIC
very verbose debugging print is performed.
Step successfully executed.
const tree_nodeRef CGetTreeReindex(const unsigned int i) const
Return a tree_reindex wrapping the i-th tree_node.
#define GET_CLASS(obj)
Macro returning the actual type of an object.
void ReplaceTreeNode(const tree_nodeRef &stmt, const tree_nodeRef &old_node, const tree_nodeRef &new_node)
Replace the occurrences of tree node old_node with new_node in statement identified by tn...
This struct specifies the statement_list node.
Definition: tree_node.hpp:4662
#define BB_EXIT
constant identifying the basic block node of type exit
Definition of the class representing a generic C application.
refcount< tree_manipulation > tree_manipulationRef
RelationshipType
The relationship type.
Source must be executed to satisfy target.
static std::string GetString(const enum kind k)
Given a kind, return the corresponding string.
Definition: tree_node.cpp:120
static tree_nodeConstRef CGetElements(const tree_nodeConstRef &type)
Given an array or a vector return the element type.
Base class to model interfaces for high-level synthesis.
std::map< unsigned int, blocRef > list_of_bloc
list_of_bloc field is the list of basic block. If this field is null then the list_of_stmt field is n...
Definition: tree_node.hpp:4673
#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
void replace_with_memset(tree_nodeRef stmt, const statement_list *sl, tree_manipulationRef tree_man) const
Data structure describing a basic block at tree level.
~compute_implicit_calls() override
Destructor.
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 max
Definition: backprop.h:17
std::string ToString(ActorGraphBackend_Type actor_graph_backend_type)
Header include.
std::string GetSignature() const override
Return the signature of this step.
#define MEMSET
constant string identifying the operation performed when two objects are memsetted.
Definition: op_graph.hpp:320
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.
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
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 ...
const unsigned int index
Represent the index read from the raw file and the index-1 of the vector of tree_node associated to t...
Definition: tree_node.hpp:146
tree_nodeRef CreateUniqueIntegerCst(integer_cst_t value, const tree_nodeConstRef &type)
memoization of integer constants
std::pair< tree_nodeRef, unsigned int > DefEdge
The type of the def edge.
Definition: tree_node.hpp:3750
compute_implicit_calls(const ParameterConstRef parameters, const application_managerRef AppM, unsigned int _function_id, const DesignFlowManagerConstRef design_flow_manager)
Constructor.
#define BB_ENTRY
constant identifying the basic block node of type entry
static bool IsVectorType(const tree_nodeConstRef &type)
Return true if the treenode is a vector.
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
Classes specification of the tree_node data structures.
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
Call graph hierarchy.
Class defining some useful functions to create tree nodes and to manipulate the tree manager...
#define DEBUG_LEVEL_NONE
no debugging print is performed.
This struct specifies the block node.
Definition: tree_node.hpp:1820
This file collects some utility functions.
const unsigned int function_id
The index of the function to be analyzed.
static tree_nodeConstRef GetBaseVariable(const tree_nodeConstRef &mem)
Retrun the base variable of a memory access.
const application_managerRef AppM
The application manager.
struct definition of the type node structures.
Definition: tree_node.hpp:1318
Class specification of the tree_reindex support class.
tree_nodeRef create_gimple_call(const tree_nodeConstRef &called_function, const std::vector< tree_nodeRef > &args, unsigned int function_decl_nid, const std::string &srcp) const
GIMPLE_CALL.
Data structures used in operations graph.
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.
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.
void replace_with_memcpy(tree_nodeRef stmt, const statement_list *sl, tree_manipulationRef tree_man) const
refcount< tree_node > tree_nodeRef
RefCount type definition of the tree_node class structure.
Definition: tree_node.hpp:212
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.
tree_managerRef TM
The tree manager.
tree_nodeRef CreateGimpleAssignAddrExpr(const tree_nodeConstRef &tn, unsigned int function_decl_nid, const std::string &srcp) const
Create a gimple_assign with op0 a new ssa_name, and op1 an addr_expr which takes the address of the t...
Determine variables to be stored in memory.
#define GET_INDEX_CONST_NODE(t)
Definition: tree_node.hpp:363
DesignFlowStep_Status InternalExec() override
Determines the variables that require a memory access.
tree_nodeRef GetFunction(const std::string &function_name) const
Return the index of a function given its name.
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.
int sl
Definition: adpcm.c:105
#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