PandA-2024.02
HWCallInjection.cpp
Go to the documentation of this file.
1 /*
2  * _/_/_/ _/_/ _/ _/ _/_/_/ _/_/
3  * _/ _/ _/ _/ _/_/ _/ _/ _/ _/ _/
4  * _/_/_/ _/_/_/_/ _/ _/_/ _/ _/ _/_/_/_/
5  * _/ _/ _/ _/ _/ _/ _/ _/ _/
6  * _/ _/ _/ _/ _/ _/_/_/ _/ _/
7  *
8  * ***********************************************
9  * PandA Project
10  * URL: http://panda.dei.polimi.it
11  * Politecnico di Milano - DEIB
12  * System Architectures Group
13  * ***********************************************
14  * Copyright (C) 2004-2024 Politecnico di Milano
15  *
16  * This file is part of the PandA framework.
17  *
18  * The PandA framework is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 3 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program. If not, see <http://www.gnu.org/licenses/>.
30  */
31 
32 #include "HWCallInjection.hpp"
33 
34 #include "Parameter.hpp"
35 #include "application_manager.hpp"
36 #include "behavioral_helper.hpp"
37 #include "op_graph.hpp"
38 #include "tree_basic_block.hpp"
39 #include "tree_helper.hpp"
40 #include "tree_manager.hpp"
41 #include "tree_manipulation.hpp"
42 #include "tree_node.hpp"
43 #include "tree_reindex.hpp"
44 
46 #include "dbgPrintHelper.hpp" // for DEBUG_LEVEL_
47 #include "string_manipulation.hpp" // for GET_CLASS
48 #include "token_interface.hpp"
49 
51 #include <string>
52 
54 #include "custom_set.hpp"
55 #include <utility>
56 #include <vector>
57 
59 
60 HWCallInjection::HWCallInjection(const ParameterConstRef Param, const application_managerRef _AppM, unsigned int funId,
61  const DesignFlowManagerConstRef DFM)
62  : FunctionFrontendFlowStep(_AppM, funId, HWCALL_INJECTION, DFM, Param)
63 {
64  debug_level = parameters->get_class_debug_level(GET_CLASS(*this), DEBUG_LEVEL_NONE);
65 }
66 
68 
71 {
73  switch(RT)
74  {
76  {
77  break;
78  }
80  {
81  break;
82  }
84  {
85  break;
86  }
87  default:
88  {
89  THROW_UNREACHABLE("HWCallInjection::ComputeFrontendRelationships");
90  }
91  }
92  return relationships;
93 }
94 
96 {
97  return bb_version == 0;
98 }
99 
101 {
102  const auto TM = AppM->get_tree_manager();
103  const auto fd = GetPointer<const function_decl>(TM->CGetTreeNode(function_id));
104  THROW_ASSERT(fd && fd->body, "Node is not a function or it hasn't a body");
105  const auto sl = GetPointerS<statement_list>(GET_NODE(fd->body));
106  THROW_ASSERT(sl, "Body is not a statement_list");
107 
108  const auto isHardwareCall = [&](const tree_nodeRef& expr) -> bool {
109  THROW_ASSERT(expr->get_kind() != tree_reindex_K, "");
111  if(expr->get_kind() == gimple_call_K)
112  {
113  const auto GC = GetPointerS<gimple_call>(expr);
114  FD = GetPointer<const addr_expr>(GET_CONST_NODE(GC->fn)) ?
115  GetPointerS<const addr_expr>(GET_CONST_NODE(GC->fn))->op :
116  GC->fn;
117  }
118  else if(expr->get_kind() == gimple_assign_K)
119  {
120  const auto GA = GetPointerS<const gimple_assign>(expr);
121  if(GET_CONST_NODE(GA->op1)->get_kind() == call_expr_K ||
122  GET_CONST_NODE(GA->op1)->get_kind() == aggr_init_expr_K)
123  {
124  const auto CE = GetPointerS<const call_expr>(GET_CONST_NODE(GA->op1));
125  FD = GetPointer<const addr_expr>(GET_CONST_NODE(CE->fn)) ?
126  GetPointerS<const addr_expr>(GET_CONST_NODE(CE->fn))->op :
127  CE->fn;
128  }
129  }
130 
131  // When the instruction is not a function call return false.
132  bool result = false;
133  if(FD)
134  {
135  if(GET_CONST_NODE(FD)->get_kind() == function_decl_K)
136  {
137  const auto FDPtr = GetPointerS<const function_decl>(GET_CONST_NODE(FD));
138  result = FDPtr->hwcall_flag;
139  if(!result)
140  {
141  const auto cmdArg = parameters->getOption<std::string>(OPT_additional_top);
142  const auto additionalTops = SplitString(cmdArg, ",");
143  const auto name = tree_helper::print_function_name(TM, FDPtr);
144  result |= std::find(additionalTops.begin(), additionalTops.end(), name) != additionalTops.end();
145  }
146  }
147  else if(GET_CONST_NODE(FD)->get_kind() == ssa_name_K)
148  {
149  // This is the case for function pointers call.
150  result = true;
151  }
152  }
153  return result;
154  };
155 
156  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Searching for hardware implemented calls");
157  for(const auto& block : sl->list_of_bloc)
158  {
159  const auto list_of_stmt = block.second->CGetStmtList();
160  auto stmt = list_of_stmt.begin();
161  while(stmt != list_of_stmt.end())
162  {
163  stmt++;
164  const auto& cur_stmt = *std::prev(stmt);
165  if(isHardwareCall(GET_NODE(cur_stmt)))
166  {
167  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Transforming call " + STR(cur_stmt));
168  buildBuiltinCall(block.second, cur_stmt);
170  }
171  }
172  }
175 }
176 
177 void HWCallInjection::buildBuiltinCall(const blocRef& block, const tree_nodeRef& stmt)
178 {
179  const auto stmt_kind = GET_NODE(stmt)->get_kind();
180  const auto TM = AppM->get_tree_manager();
181  const auto IRman = tree_manipulationRef(new tree_manipulation(TM, parameters, AppM));
182 
184  {
185  const auto vararg_list_idx = TM->new_tree_node_id();
186  std::map<TreeVocabularyTokenTypes_TokenEnum, std::string> attr_map;
187  attr_map[TOK(TOK_VALU)] = STR(GET_INDEX_NODE(IRman->GetSignedIntegerType()));
188  TM->create_tree_node(vararg_list_idx, tree_list_K, attr_map);
189  attr_map.clear();
190 
191  const auto ftype_idx = TM->new_tree_node_id();
192  attr_map[TOK(TOK_RETN)] = STR(GET_INDEX_NODE(IRman->GetVoidType()));
193  attr_map[TOK(TOK_VARARGS)] = STR(1);
194  attr_map[TOK(TOK_PRMS)] = STR(vararg_list_idx);
195  const auto funTypeSize = TM->CreateUniqueIntegerCst(8, IRman->GetSignedIntegerType());
196  attr_map[TOK(TOK_SIZE)] = STR(GET_INDEX_CONST_NODE(funTypeSize));
197  attr_map[TOK(TOK_ALIGNED)] = STR(8);
198  TM->create_tree_node(ftype_idx, function_type_K, attr_map);
199  attr_map.clear();
200 
201  builtinWaitCallDeclIdx = TM->new_tree_node_id();
202  attr_map[TOK(TOK_TYPE)] = STR(ftype_idx);
203  const auto builtinIdString = IRman->create_identifier_node(BUILTIN_WAIT_CALL);
204  attr_map[TOK(TOK_NAME)] = STR(GET_INDEX_CONST_NODE(builtinIdString));
205  attr_map[TOK(TOK_SRCP)] = BUILTIN_SRCP;
206  TM->create_tree_node(builtinWaitCallDeclIdx, function_decl_K, attr_map);
207  attr_map.clear();
208  }
209 
210  const auto gn = GetPointerS<gimple_node>(GET_NODE(stmt));
211  const auto srcp_str = gn->include_name + ":" + STR(gn->line_number) + ":" + STR(gn->column_number);
212 
213  const auto builtin_stmt_idx = TM->new_tree_node_id();
214  {
215  const auto addr_expr_idx = TM->new_tree_node_id();
216  std::map<TreeVocabularyTokenTypes_TokenEnum, std::string> attr_map;
217  const auto functionDecl = GetPointerS<const function_decl>(TM->CGetTreeNode(builtinWaitCallDeclIdx));
218  attr_map[TOK(TOK_TYPE)] = STR(GET_INDEX_NODE(IRman->GetPointerType(functionDecl->type, 8)));
219  attr_map[TOK(TOK_OP)] = STR(builtinWaitCallDeclIdx);
220  attr_map[TOK(TOK_SRCP)] = srcp_str;
221  TM->create_tree_node(addr_expr_idx, addr_expr_K, attr_map);
222  attr_map.clear();
223 
224  attr_map[TOK(TOK_FN)] = STR(addr_expr_idx);
225  if(stmt_kind == gimple_call_K)
226  {
227  const auto GC = GetPointerS<const gimple_call>(GET_NODE(stmt));
228  attr_map[TOK(TOK_SCPE)] = STR(GET_INDEX_NODE(GC->scpe));
229  }
230  else if(stmt_kind == gimple_assign_K)
231  {
232  const auto GA = GetPointerS<const gimple_assign>(GET_NODE(stmt));
233  attr_map[TOK(TOK_SCPE)] = STR(GET_INDEX_NODE(GA->scpe));
234  }
235  attr_map[TOK(TOK_SRCP)] = srcp_str;
236  TM->create_tree_node(builtin_stmt_idx, gimple_call_K, attr_map);
237  }
238 
239  const auto builtin_stmt = TM->GetTreeReindex(builtin_stmt_idx);
240  const auto builtin_call = GetPointerS<gimple_call>(GET_NODE(builtin_stmt));
241  tree_nodeRef retVar = nullptr;
242  if(stmt_kind == gimple_call_K)
243  {
244  const auto GC = GetPointerS<gimple_call>(GET_NODE(stmt));
245  builtin_call->AddArg(GC->fn);
246 
247  const auto has_return = TM->CreateUniqueIntegerCst(0, IRman->GetSignedIntegerType());
248  builtin_call->AddArg(has_return);
249 
250  for(const auto& arg : GC->args)
251  {
252  builtin_call->AddArg(arg);
253  }
254 
255  builtin_call->memuse = GC->memuse;
256  builtin_call->memdef = GC->memdef;
257  builtin_call->vdef = GC->vdef;
258  builtin_call->vuses = GC->vuses;
259  builtin_call->vovers = GC->vovers;
260 
261  builtin_call->pragmas = GC->pragmas;
262  builtin_call->use_set = GC->use_set;
263  builtin_call->clobbered_set = GC->clobbered_set;
264  builtin_call->scpe = GC->scpe;
265  builtin_call->bb_index = GC->bb_index;
266  builtin_call->include_name = GC->include_name;
267  builtin_call->line_number = GC->line_number;
268  builtin_call->column_number = GC->column_number;
269  }
270  else if(stmt_kind == gimple_assign_K)
271  {
272  const auto GA = GetPointerS<gimple_assign>(GET_NODE(stmt));
273  if(GET_NODE(GA->op1)->get_kind() == call_expr_K || GET_NODE(GA->op1)->get_kind() == aggr_init_expr_K)
274  {
275  const auto CE = GetPointerS<const call_expr>(GET_CONST_NODE(GA->op1));
276  builtin_call->AddArg(CE->fn);
277 
278  const auto has_return = TM->CreateUniqueIntegerCst(1, IRman->GetSignedIntegerType());
279  builtin_call->AddArg(has_return);
280 
281  for(const auto& arg : CE->args)
282  {
283  builtin_call->AddArg(arg);
284  }
285 
286  if(const auto ssaRet = GetPointer<const ssa_name>(GET_CONST_NODE(GA->op0)))
287  {
288  tree_nodeRef ret_var_type, ret_var_size;
289  unsigned int ret_var_algn;
290  if(ssaRet->type)
291  {
292  ret_var_type = ssaRet->type;
293  ret_var_size = GetPointerS<const type_node>(GET_CONST_NODE(ssaRet->type))->size;
294  ret_var_algn = GetPointerS<const type_node>(GET_CONST_NODE(ssaRet->type))->algn;
295  }
296  else
297  {
298  const auto vd = GetPointerS<const var_decl>(GET_CONST_NODE(ssaRet->var));
299  ret_var_type = vd->type;
300  ret_var_size = GetPointerS<const type_node>(GET_CONST_NODE(vd->type))->size;
301  ret_var_algn = GetPointerS<const type_node>(GET_CONST_NODE(vd->type))->algn;
302  }
303  retVar = IRman->create_var_decl(
304  IRman->create_identifier_node("__return_value"), ret_var_type, GA->scpe, ret_var_size, nullptr, nullptr,
305  STR(GA->include_name + ":" + STR(GA->line_number) + ":" + STR(GA->column_number)), ret_var_algn, 1,
306  true);
307 
308  GA->op1 = retVar;
309  }
310 
311  if(!retVar)
312  {
313  retVar = GA->op0;
314  }
315 
316  const auto addrExprReturnValue = TM->new_tree_node_id();
317  {
318  std::map<TreeVocabularyTokenTypes_TokenEnum, std::string> addrExprReturnValueMap;
319  const auto typeRetVar = tree_helper::CGetType(retVar);
320  addrExprReturnValueMap[TOK(TOK_TYPE)] = STR(GET_INDEX_NODE(IRman->GetPointerType(typeRetVar)));
321  addrExprReturnValueMap[TOK(TOK_OP)] = STR(GET_INDEX_CONST_NODE(retVar));
322  addrExprReturnValueMap[TOK(TOK_SRCP)] = srcp_str;
323  TM->create_tree_node(addrExprReturnValue, addr_expr_K, addrExprReturnValueMap);
324  }
325  builtin_call->AddArg(TM->GetTreeReindex(addrExprReturnValue));
326 
327  builtin_call->memdef = GA->memdef;
328  builtin_call->memuse = GA->memuse;
329  builtin_call->vdef = GA->vdef;
330  builtin_call->vuses = GA->vuses;
331  builtin_call->vovers = GA->vovers;
332 
333  builtin_call->pragmas = GA->pragmas;
334  builtin_call->use_set = GA->use_set;
335  builtin_call->clobbered_set = GA->clobbered_set;
336  builtin_call->scpe = GA->scpe;
337  builtin_call->bb_index = GA->bb_index;
338  builtin_call->include_name = GA->include_name;
339  builtin_call->line_number = GA->line_number;
340  builtin_call->column_number = GA->column_number;
341 
342  GA->memdef = nullptr;
343  GA->memuse = builtin_call->memdef;
344  GA->vdef = nullptr;
345  GA->vuses.clear();
346  GA->vovers.clear();
347  THROW_ASSERT(builtin_call->vdef, "Unexpected condition");
348  GA->AddVuse(builtin_call->vdef);
349 
350  GA->pragmas.clear();
351  GA->use_set = PointToSolutionRef(new PointToSolution());
352  GA->clobbered_set = PointToSolutionRef(new PointToSolution());
353  }
354  }
355  else
356  {
357  THROW_UNREACHABLE("Error not a gimple call or assign statement!");
358  }
359 
361  "---Added to BB" + STR(block->number) + " " + STR(builtin_stmt));
362  block->PushBefore(builtin_stmt, stmt, AppM);
363  if(!retVar)
364  {
366  "---Removed from BB" + STR(block->number) + " " + STR(stmt));
367  block->RemoveStmt(stmt, AppM);
368  }
369  else
370  {
371  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Modified " + STR(stmt));
372  }
373 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
static unsigned int builtinWaitCallDeclIdx
parser/compiler include
This struct specifies a point-to solution.
Definition: tree_node.hpp:1001
refcount< PointToSolution > PointToSolutionRef
Definition: tree_node.hpp:1073
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
void buildBuiltinCall(const blocRef &block, const tree_nodeRef &stmt)
#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 GET_CLASS(obj)
Macro returning the actual type of an object.
HWCallInjection(const ParameterConstRef Param, const application_managerRef AppM, unsigned int funId, const DesignFlowManagerConstRef DFM)
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
Definition of the class representing a generic C application.
refcount< tree_manipulation > tree_manipulationRef
const std::vector< std::string > SplitString(const std::string &input, const std::string &separators)
Function which splits a string into tokens.
RelationshipType
The relationship type.
Source must be executed to satisfy target.
A simple interface to token object of the raw files.
#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.
Data structure describing a basic block at tree level.
unsigned int bb_version
The version of the basic block intermediate representation on which this step has been applied...
#define TOK(token)
Macro used to convert a token symbol into a treeVocabularyTokenTypes.
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
~HWCallInjection() override
#define FD(x)
Definition: aes.c:8
redefinition of set to manage ordered/unordered structures
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
const CustomUnorderedSet< std::pair< FrontendFlowStepType, FunctionRelationship > > ComputeFrontendRelationships(const DesignFlowStep::RelationshipType RT) const override
Return the set of analyses in relationship with this design step.
Classes specification of the tree_node data structures.
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
Class defining some useful functions to create tree nodes and to manipulate the tree manager...
#define DEBUG_LEVEL_NONE
no debugging print is performed.
int result[SIZE]
Definition: adpcm.c:800
This struct specifies the block node.
Definition: tree_node.hpp:1820
This file collects some utility functions.
DesignFlowStep_Status InternalExec() override
Execute the step.
#define BUILTIN_SRCP
const unsigned int function_id
The index of the function to be analyzed.
const application_managerRef AppM
The application manager.
Class specification of the tree_reindex support class.
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.
this class is used to manage the command-line or XML options.
int debug_level
The debug level.
#define GET_INDEX_CONST_NODE(t)
Definition: tree_node.hpp:363
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.
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:52 for PandA-2024.02 by doxygen 1.8.13