PandA-2024.02
pragma_manager.cpp
Go to the documentation of this file.
1 /*
2  *
3  * _/_/_/ _/_/ _/ _/ _/_/_/ _/_/
4  * _/ _/ _/ _/ _/_/ _/ _/ _/ _/ _/
5  * _/_/_/ _/_/_/_/ _/ _/_/ _/ _/ _/_/_/_/
6  * _/ _/ _/ _/ _/ _/ _/ _/ _/
7  * _/ _/ _/ _/ _/ _/_/_/ _/ _/
8  *
9  * ***********************************************
10  * PandA Project
11  * URL: http://panda.dei.polimi.it
12  * Politecnico di Milano - DEIB
13  * System Architectures Group
14  * ***********************************************
15  * Copyright (C) 2004-2024 Politecnico di Milano
16  *
17  * This file is part of the PandA framework.
18  *
19  * The PandA framework is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 3 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program. If not, see <http://www.gnu.org/licenses/>.
31  *
32  */
44 #include "config_HAVE_FROM_PRAGMA_BUILT.hpp"
46 #include "config_NPROFILE.hpp"
47 
49 #include "pragma_manager.hpp"
50 
52 #include "application_manager.hpp"
53 #include "basic_block.hpp"
54 #include "behavioral_helper.hpp"
55 #include "function_behavior.hpp"
56 #include "loop.hpp"
57 #include "loops.hpp"
58 #include "op_graph.hpp"
59 
61 #include "pragma_constants.hpp"
62 
64 #include "graph.hpp"
65 
67 #include "Parameter.hpp"
68 
70 #include "PragmaParser.hpp"
71 
73 #include "token_interface.hpp"
74 
76 #include <string>
77 
79 #include "custom_map.hpp"
80 #include <list>
81 #include <vector>
82 
84 #include "ext_tree_node.hpp"
85 #include "tree_basic_block.hpp"
86 #include "tree_helper.hpp"
87 #include "tree_manager.hpp"
88 #include "tree_node.hpp"
89 #include "tree_reindex.hpp"
90 #include "var_pp_functor.hpp"
91 
93 #include "cpu_time.hpp"
94 #include "dbgPrintHelper.hpp"
95 #include "exceptions.hpp"
96 #include "string_manipulation.hpp" // for GET_CLASS
97 #include <boost/algorithm/string.hpp>
98 #include <boost/graph/depth_first_search.hpp>
99 #include <boost/graph/reverse_graph.hpp>
100 #include <regex>
101 
103  "atomic", "barrier", "critical", "declare simd", "for", "parallel for", "parallel sections",
104  "parallel", "sections", "section", "simd", "target", "task",
105 };
106 
107 unsigned int num_task = 0;
108 
110  : application_manager(_application_manager),
111  TM(_application_manager->get_tree_manager()),
112  param(_param),
113  debug_level(_param->get_class_debug_level(GET_CLASS(*this)))
114 {
115  if(param->isOption(OPT_blackbox))
116  {
117  const auto black_box_functions = param->getOption<CustomSet<std::string>>(OPT_blackbox);
118  for(const auto& black_box_function : black_box_functions)
119  {
120  PRINT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, param->getOption<int>(OPT_output_level),
121  "Function \"" + black_box_function + "\" is a blackbox");
122  BlackBoxFunctions.insert(black_box_function);
123  // addBlackBoxPragma(black_box_function);
124  }
125  }
126 }
127 
129 
131 {
132  PRINT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "Checking source code compliance...");
133 
134  // here check for reference manual compliance
135 
136  return true;
137 }
138 
139 bool pragma_manager::isBlackBox(const std::string& name) const
140 {
141  return BlackBoxFunctions.find(name) != BlackBoxFunctions.end();
142 }
143 
144 const std::list<std::string> pragma_manager::GetFunctionDefinitionPragmas(const std::string& function_name) const
145 {
146  if(function_definition_pragmas.find(function_name) != function_definition_pragmas.end())
147  {
148  return function_definition_pragmas.find(function_name)->second;
149  }
150  return std::list<std::string>();
151 }
152 
154 {
155  if(FunctionCallPragmas.find(Name) != FunctionCallPragmas.end())
156  {
157  return FunctionCallPragmas.find(Name)->second;
158  }
159  else
160  {
162  }
163 }
164 
165 void pragma_manager::AddFunctionDefinitionPragmas(const std::string& function_name,
166  const CustomUnorderedSet<std::string>& pragmas)
167 {
168  for(const auto& pragma : pragmas)
169  {
170  std::match_results<std::string::const_iterator> what;
171  std::regex expr;
172  if(pragma.find("#pragma omp declare simd") == 0)
173  {
174  function_definition_pragmas[function_name].push_back(pragma);
175  continue;
176  }
177  THROW_ERROR("Unsupported function definition pragma associated with function " + function_name + ": " + pragma);
178  }
179 }
180 
181 void pragma_manager::addFunctionCallPragmas(const std::string& Name, const CustomUnorderedSet<std::string>& Pragmas)
182 {
183  CustomUnorderedSet<std::string>::const_iterator k, k_end = Pragmas.end();
184  for(k = Pragmas.begin(); k != k_end; ++k)
185  {
186  FunctionCallPragmas[Name].insert(*k);
187  }
188 }
189 
190 unsigned int pragma_manager::addBlackBoxPragma(const std::string& function_name, unsigned int function_id)
191 {
192  unsigned int scope = TM->new_tree_node_id();
193  std::map<TreeVocabularyTokenTypes_TokenEnum, std::string> tree_node_schema;
194  TM->create_tree_node(scope, issue_pragma_K, tree_node_schema);
195 
196  unsigned int directive = TM->new_tree_node_id();
197  TM->create_tree_node(directive, blackbox_pragma_K, tree_node_schema);
198 
199  std::map<TreeVocabularyTokenTypes_TokenEnum, std::string> schema;
200  schema[TOK(TOK_SRCP)] = ":0:0";
201  schema[TOK(TOK_SCPE)] = STR(function_id);
202  schema[TOK(TOK_IS_BLOCK)] = STR(false);
203  schema[TOK(TOK_OPEN)] = STR(false);
204  schema[TOK(TOK_PRAGMA_SCOPE)] = std::to_string(scope);
205  schema[TOK(TOK_PRAGMA_DIRECTIVE)] = std::to_string(directive);
206  unsigned int final_id = TM->new_tree_node_id();
207  TM->create_tree_node(final_id, gimple_pragma_K, schema);
208 
209  BlackBoxFunctions.insert(function_name);
210 
211  return final_id;
212 }
213 
214 unsigned int pragma_manager::AddOmpSimdPragma(const std::string& line, unsigned int function_id) const
215 {
216  std::map<TreeVocabularyTokenTypes_TokenEnum, std::string> simd_tree_node_schema, omp_pragma_tree_node_schema,
217  tree_node_schema;
218  unsigned int scope_id = TM->new_tree_node_id();
219  TM->create_tree_node(scope_id, omp_pragma_K, omp_pragma_tree_node_schema);
220 
221  unsigned int simd_id = TM->new_tree_node_id();
222  TM->create_tree_node(simd_id, omp_simd_pragma_K, simd_tree_node_schema);
223  auto* osp = GetPointer<omp_simd_pragma>(TM->get_tree_node_const(simd_id));
224  if(line != "#pragma omp declare simd")
225  {
226  osp->clauses = ExtractClauses(line.substr(line.find("#pragma omp declare simd ")));
227  }
228 
229  tree_node_schema[TOK(TOK_IS_BLOCK)] = STR(true);
230  tree_node_schema[TOK(TOK_OPEN)] = STR(false);
231  tree_node_schema[TOK(TOK_PRAGMA_SCOPE)] = std::to_string(scope_id);
232  tree_node_schema[TOK(TOK_PRAGMA_DIRECTIVE)] = std::to_string(simd_id);
233  tree_node_schema[TOK(TOK_BB_INDEX)] = std::to_string(0);
234  tree_node_schema[TOK(TOK_SRCP)] = ":0:0";
235  tree_node_schema[TOK(TOK_SCPE)] = STR(function_id);
236  unsigned int pragma_id = TM->new_tree_node_id();
237  TM->create_tree_node(pragma_id, gimple_pragma_K, tree_node_schema);
238  return pragma_id;
239 }
240 
242 pragma_manager::ExtractClauses(const std::string& clauses_list) const
243 {
245  if(!clauses_list.size())
246  {
247  return clauses_map;
248  }
249 
250  std::string trimmed_clauses = clauses_list;
251  bool inside_parentheses = false;
253  for(size_t index = clauses_list.size(); index > 0; index--)
254  {
255  if(trimmed_clauses[index - 1] == ')')
256  {
257  inside_parentheses = true;
258  }
259  else if(trimmed_clauses[index - 1] == '(')
260  {
261  inside_parentheses = false;
262  index--;
263  if(index == 0)
264  {
265  break;
266  }
267  for(; index > 0 && trimmed_clauses[index - 1] == ' '; index--)
268  {
269  trimmed_clauses.erase(index - 1, 1);
270  }
271  }
272  else if(trimmed_clauses[index - 1] == ' ' && inside_parentheses)
273  {
274  trimmed_clauses.erase(index - 1, 1);
275  }
276  }
277 
278  std::vector<std::string> splitted = SplitString(trimmed_clauses, " \t\n");
279 
280  for(const auto& clause : splitted)
281  {
282  if(clause.find('(') != std::string::npos)
283  {
284  const std::string key = clause.substr(0, clause.find('('));
285  const std::string value = clause.substr(clause.find('(') + 1, clause.size() - clause.find('(') - 2);
286  clauses_map[key] = value;
287  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Clause " + key + ": " + value);
288  }
289  else
290  {
291  clauses_map[clause] = "";
292  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Empty clause " + clause);
293  }
294  }
295  return clauses_map;
296 }
297 
298 void pragma_manager::setGenericPragma(unsigned int number, const std::string& line)
299 {
300  GenericPragmas[number] = line;
301 }
302 
303 std::string pragma_manager::getGenericPragma(unsigned int number) const
304 {
305  THROW_ASSERT(GenericPragmas.count(number), "Wrong generic pragma");
306  return GenericPragmas.find(number)->second;
307 }
308 
309 bool pragma_manager::CheckOmpFor(const application_managerConstRef app_man, const unsigned int function_index,
310  const vertex bb_operation_vertex) const
311 {
312  const BBGraphConstRef bb_cfg = app_man->CGetFunctionBehavior(function_index)->CGetBBGraph(FunctionBehavior::BB);
313  vertex current = bb_operation_vertex;
315  "-->Looking for an openmp associated with loop " +
316  std::to_string(bb_cfg->CGetBBNodeInfo(bb_operation_vertex)->block->number));
317  while(boost::in_degree(current, *bb_cfg) == 1)
318  {
319  const BBNodeInfoConstRef info = bb_cfg->CGetBBNodeInfo(current);
320  for(const auto& stmt : info->block->CGetStmtList())
321  {
322  if(GET_NODE(stmt)->get_kind() == gimple_pragma_K)
323  {
324  auto* pn = GetPointer<gimple_pragma>(GET_NODE(stmt));
325  if(pn->scope && GetPointer<omp_pragma>(GET_NODE(pn->scope)))
326  {
327  auto* fp = GetPointer<omp_for_pragma>(GET_NODE(pn->directive));
328  if(fp)
329  {
330  return true;
331  }
332  }
333  }
334  }
335  InEdgeIterator ei, ei_end;
336  boost::tie(ei, ei_end) = boost::in_edges(current, *bb_cfg);
337  current = boost::source(*ei, *bb_cfg);
338  }
340  return false;
341 }
342 
343 void pragma_manager::CheckAddOmpFor(const unsigned int function_index, const vertex bb_operation_vertex,
344  const application_managerRef AppM)
345 {
346  const auto bb_cfg = application_manager->CGetFunctionBehavior(function_index)->CGetBBGraph(FunctionBehavior::BB);
347  vertex current = bb_operation_vertex;
349  "-->Looking for an openmp associated with loop " +
350  std::to_string(bb_cfg->CGetBBNodeInfo(bb_operation_vertex)->block->number));
351  while(boost::in_degree(current, *bb_cfg) == 1)
352  {
353  const auto info = bb_cfg->CGetBBNodeInfo(current);
354  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Analyzing BB" + STR(info->block->number));
355  for(const auto& stmt : info->block->CGetStmtList())
356  {
357  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Analzying " + STR(stmt));
358  if(GET_NODE(stmt)->get_kind() == gimple_pragma_K)
359  {
360  const auto pn = GetPointerS<gimple_pragma>(GET_NODE(stmt));
361  if(pn->scope && GetPointer<omp_pragma>(GET_NODE(pn->scope)))
362  {
363  const auto fp = GetPointer<omp_for_pragma>(GET_NODE(pn->directive));
364  if(fp)
365  {
366  info->block->RemoveStmt(stmt, AppM);
367  const auto FB = application_manager->GetFunctionBehavior(function_index);
368  FB->GetLoops()->GetLoop(bb_cfg->CGetBBNodeInfo(bb_operation_vertex)->block->number)->loop_type |=
369  DOALL_LOOP;
370  // FB->UpdateBBVersion();
372  return;
373  }
374  }
375  }
376  }
377  InEdgeIterator ei, ei_end;
378  boost::tie(ei, ei_end) = boost::in_edges(current, *bb_cfg);
379  current = boost::source(*ei, *bb_cfg);
380  }
382 }
383 
384 void pragma_manager::CheckAddOmpSimd(const unsigned int function_index, const vertex bb_operation_vertex,
385  const application_managerRef AppM)
386 {
387  const auto bb_cfg = application_manager->GetFunctionBehavior(function_index)->GetBBGraph(FunctionBehavior::BB);
388  const auto current_loop_id = bb_cfg->CGetBBNodeInfo(bb_operation_vertex)->loop_id;
390  "-->Looking for an openmp simd associated with loop " +
391  std::to_string(bb_cfg->CGetBBNodeInfo(bb_operation_vertex)->block->number));
392  if(boost::in_degree(bb_operation_vertex, *bb_cfg) != 1)
393  {
395  return;
396  }
397  InEdgeIterator ei, ei_end;
398  boost::tie(ei, ei_end) = boost::in_edges(bb_operation_vertex, *bb_cfg);
399  vertex current = boost::source(*ei, *bb_cfg);
400  while(boost::in_degree(current, *bb_cfg) == 1)
401  {
402  const auto info = bb_cfg->GetBBNodeInfo(current);
403  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Analyzing BB" + STR(info->block->number));
404  for(const auto& stmt : info->block->CGetStmtList())
405  {
406  if(GET_NODE(stmt)->get_kind() == gimple_pragma_K)
407  {
408  const auto pn = GetPointerS<gimple_pragma>(GET_NODE(stmt));
409  if(pn->scope && GetPointer<omp_pragma>(GET_NODE(pn->scope)))
410  {
411  const auto sp = GetPointer<omp_simd_pragma>(GET_NODE(pn->directive));
412  if(sp)
413  {
414  info->block->RemoveStmt(stmt, AppM);
415  if(pn->vdef)
416  {
417  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Removing vdef " + STR(pn->vdef));
418  const auto ssa_vdef = GetPointerS<ssa_name>(GET_NODE(pn->vdef));
419  const auto vdef_uses = ssa_vdef->CGetUseStmts();
420  for(const auto& stmt_uses : vdef_uses)
421  {
422  const auto gn = GetPointerS<gimple_node>(GET_NODE(stmt_uses.first));
423  if(gn->memuse && GET_INDEX_NODE(gn->memuse) == GET_INDEX_NODE(pn->vdef))
424  {
425  ssa_vdef->RemoveUse(stmt_uses.first);
426  gn->memuse = nullptr;
427  }
428  if(gn->vuses.erase(pn->vdef))
429  {
430  ssa_vdef->RemoveUse(stmt_uses.first);
431  }
432  if(gn->vovers.erase(pn->vdef))
433  {
434  ssa_vdef->RemoveUse(stmt_uses.first);
435  }
436  }
438  }
439  const auto FB = application_manager->GetFunctionBehavior(function_index);
440  FB->GetLoops()->GetLoop(bb_cfg->CGetBBNodeInfo(bb_operation_vertex)->block->number)->loop_type |=
441  DOALL_LOOP;
442  // FB->UpdateBBVersion();
444  return;
445  }
446  }
447  }
448  }
449  boost::tie(ei, ei_end) = boost::in_edges(current, *bb_cfg);
450  current = boost::source(*ei, *bb_cfg);
451  if(boost::out_degree(current, *bb_cfg) != 1 || bb_cfg->CGetBBNodeInfo(current)->loop_id != current_loop_id)
452  {
453  break;
454  }
455  }
457 }
458 
460 {
461  OmpPragmaType omp_pragma_type = OMP_UNKNOWN;
462  size_t index = 0;
463  for(index = 0; index < static_cast<size_t>(pragma_manager::OMP_UNKNOWN); index++)
464  {
465  if(directive.find(pragma_manager::omp_directive_keywords[index]) != std::string::npos)
466  {
467  omp_pragma_type = static_cast<pragma_manager::OmpPragmaType>(index);
468  break;
469  }
470  }
471  return omp_pragma_type;
472 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
static const std::string omp_directive_keywords[OMP_UNKNOWN]
The list of omp directive keywords.
TVMValue param[3]
CustomOrderedSet< std::string > BlackBoxFunctions
Basic block control flow graph.
File containing functions and utilities to support the printing of debug messagges.
const std::list< std::string > GetFunctionDefinitionPragmas(const std::string &function_name) const
Return the pragmas associated with a function definition.
#define PRINT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
const tree_managerRef TM
#define GET_CLASS(obj)
Macro returning the actual type of an object.
CustomUnorderedSet< std::string > getFunctionCallPragmas(const std::string &Name) const
Definition of the class representing a generic C application.
const std::vector< std::string > SplitString(const std::string &input, const std::string &separators)
Function which splits a string into tokens.
std::map< std::string, std::list< std::string > > function_definition_pragmas
Function defintion pragmas.
std::map< unsigned int, std::string > GenericPragmas
void addFunctionCallPragmas(const std::string &Name, const CustomUnorderedSet< std::string > &Pragmas)
const FunctionBehaviorConstRef CGetFunctionBehavior(unsigned int index) const
Returns the data-structure associated with the given identifier.
bool checkCompliant() const
Check if the data-structure information are compliant with the pragma reference manual.
Class specification of the graph structures.
CustomUnorderedMapUnstable< std::string, std::string > ExtractClauses(const std::string &clauses_list) const
Extract clauses associated with a pragma.
boost::graph_traits< graph >::in_edge_iterator InEdgeIterator
in_edge_iterator definition.
Definition: graph.hpp:1310
exceptions managed by PandA
A simple interface to token object of the raw files.
#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
absl::flat_hash_map< T, U, Hash, Eq, Alloc > CustomUnorderedMapUnstable
Definition: custom_map.hpp:156
Data structure describing a basic block at tree level.
redefinition of map to manage ordered/unordered structures
constant strings used in pragma identification
#define TOK(token)
Macro used to convert a token symbol into a treeVocabularyTokenTypes.
Include a set of utilities used to manage CPU time measures.
unsigned int addBlackBoxPragma(const std::string &function_name, unsigned int function_id)
#define STR(s)
Macro which performs a lexical_cast to a string.
void line(int x1, int y1, int x2, int y2, unsigned int color)
Definition: main.c:110
Auxiliary methods for manipulating string.
int key[32]
Definition: aes.h:67
void AddFunctionDefinitionPragmas(const std::string &name, const CustomUnorderedSet< std::string > &pragmas)
Add a set of definition pragmas to a function.
virtual ~pragma_manager()
Destructor.
std::map< std::string, CustomUnorderedSet< std::string > > FunctionCallPragmas
static const uint32_t k[]
Definition: sha-256.c:22
Manager for pragma annotations.
std::string getGenericPragma(unsigned int number) const
#define index(x, y)
Definition: Keccak.c:74
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
Classes specification of the tree_node data structures.
OmpPragmaType
The possible openmp pragmas Note that sections has to go before section but after parallel sections o...
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
bool CheckOmpFor(const application_managerConstRef app_man, const unsigned int function_index, const vertex bb_operation_vertex) const
Check if a omp for pragma is associated with the loop.
This file collects some utility functions.
void CheckAddOmpFor(const unsigned int function_index, const vertex bb_operation_vertex, const application_managerRef AppM)
Check if a omp for pragma is associated with the loop; if yes, add the gimple_for.
Parsing pragma from C sources.
unsigned int num_task
pragma_manager(const application_managerRef application_manager, const ParameterConstRef param)
Constructor.
int debug_level
The debug level.
Class specification of the tree_reindex support class.
bool isBlackBox(const std::string &name) const
FunctionBehaviorRef GetFunctionBehavior(unsigned int index)
Returns the data structure associated with the given identifier.
Class specification of the basic_block structure.
interface of a loop
const BBNodeInfoConstRef CGetBBNodeInfo(const vertex node) const
Return the info associated with a basic block.
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
const BBGraphConstRef CGetBBGraph(FunctionBehavior::bb_graph_type gt=FunctionBehavior::BB) const
This method returns the basic block graphs.
interface of loops finding algorithm
unsigned int AddOmpSimdPragma(const std::string &line, unsigned int function_id) const
Create a simd openmp pragma starting from the line containing it.
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 setGenericPragma(unsigned int number, const std::string &line)
#define DOALL_LOOP
parallelizable for loop
Definition: loop.hpp:132
#define PRINT_OUT_MEX(profLevel, curprofLevel, mex)
#define OUTPUT_LEVEL_VERBOSE
verbose debugging print is performed.
const ParameterConstRef param
Set of input parameters.
static OmpPragmaType GetOmpPragmaType(const std::string &directive)
Returns the identifier corresponding to an openmp directive.
Class specification of the manager of the tree structures extracted from the raw file.
A brief description of the C++ Header File.
void CheckAddOmpSimd(const unsigned int function_index, const vertex bb_operation_vertex, const application_managerRef AppM)
Check if a omp simd pragma is associated with the loop; if yes, add information to the loop...
#define DEBUG_LEVEL_MINIMUM
minimum debugging print is performed.
#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:55 for PandA-2024.02 by doxygen 1.8.13