PandA-2024.02
loops_analysis_bambu.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  */
41 #include "loops_analysis_bambu.hpp"
42 
43 #include "Parameter.hpp"
44 #include "application_manager.hpp"
45 #include "basic_block.hpp"
46 #include "ext_tree_node.hpp"
47 #include "function_behavior.hpp"
48 #include "loop.hpp"
49 #include "loops.hpp"
50 #include "string_manipulation.hpp"
51 #include "tree_basic_block.hpp"
52 #include "tree_helper.hpp"
53 #include "tree_manager.hpp"
54 #include "tree_reindex.hpp"
55 
56 #if HAVE_PRAGMA_BUILT
57 #include "pragma_manager.hpp"
58 #endif
59 
60 #include "config_HAVE_PRAGMA_BUILT.hpp"
61 
63  unsigned int _function_id, const DesignFlowManagerConstRef _design_flow_manager)
64  : FunctionFrontendFlowStep(_AppM, _function_id, LOOPS_ANALYSIS_BAMBU, _design_flow_manager, _parameters)
65 {
66  debug_level = parameters->get_class_debug_level(GET_CLASS(*this), DEBUG_LEVEL_NONE);
67 }
68 
70 
73 {
75  switch(relationship_type)
76  {
78  {
79  relationships.insert(std::make_pair(BB_FEEDBACK_EDGES_IDENTIFICATION, SAME_FUNCTION));
80  relationships.insert(std::make_pair(LOOPS_COMPUTATION, SAME_FUNCTION));
81  relationships.insert(std::make_pair(EXTRACT_GIMPLE_COND_OP, SAME_FUNCTION));
82  const auto is_simd = tree_helper::has_omp_simd(GetPointer<const statement_list>(
83  GET_NODE(GetPointer<const function_decl>(AppM->get_tree_manager()->CGetTreeNode(function_id))->body)));
84  if(is_simd)
85  {
86  relationships.insert(std::make_pair(SERIALIZE_MUTUAL_EXCLUSIONS, SAME_FUNCTION));
87  }
88  break;
89  }
91  {
92  break;
93  }
95  {
96  relationships.insert(std::make_pair(SIMPLE_CODE_MOTION, SAME_FUNCTION));
97  break;
98  }
99  default:
100  {
101  THROW_UNREACHABLE("");
102  }
103  }
104  return relationships;
105 }
106 
108 {
109  const auto TM = AppM->get_tree_manager();
111  const auto fbb = function_behavior->CGetBBGraph(FunctionBehavior::FBB);
112  for(const auto& loop : function_behavior->GetLoops()->GetModifiableList())
113  {
114  loop->loop_type = UNKNOWN_LOOP;
115  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Analyzing loop " + STR(loop->GetId()));
116  if(!loop->IsReducible())
117  {
118  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Loop is irreducible");
119  continue;
120  }
121  const vertex header = loop->GetHeader();
122 #if HAVE_PRAGMA_BUILT
123  const auto PM = AppM->get_pragma_manager();
124  if(PM)
125  {
126  PM->CheckAddOmpFor(function_id, header, AppM);
127  PM->CheckAddOmpSimd(function_id, header, AppM);
128  }
129 #endif
130  const auto nexit = loop->num_exits();
131  if(nexit != 1)
132  {
133  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Multiple exits loop");
134  continue;
135  }
136  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Single exit loop considered");
137  loop->loop_type |= SINGLE_EXIT_LOOP;
138  const auto exit_vertex = *loop->exit_block_iter_begin();
139  bool do_while = false;
140  if(exit_vertex == header && loop->num_blocks() != 1)
141  {
143  loop->loop_type &= ~UNKNOWN_LOOP;
144  loop->loop_type |= WHILE_LOOP;
145  }
146  else
147  {
149  loop->loop_type &= ~UNKNOWN_LOOP;
150  loop->loop_type |= DO_WHILE_LOOP;
151  do_while = true;
152  }
154  const tree_nodeRef last_stmt = GET_NODE(fbb->CGetBBNodeInfo(exit_vertex)->block->CGetStmtList().back());
155  if(last_stmt->get_kind() != gimple_cond_K)
156  {
157  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Multi way if in the header");
158  continue;
159  }
160  const auto SPBE = loop->get_sp_back_edges();
161  if(SPBE.size() > 1)
162  {
163  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--More than one feedback edge");
164  continue;
165  }
166  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Single feedback loop");
167  const auto sourceSPBE1 = SPBE.begin()->first;
168  const unsigned int sourceSPBE1_index = fbb->CGetBBNodeInfo(sourceSPBE1)->block->number;
169  EdgeDescriptor e;
170  bool found;
171  boost::tie(e, found) = boost::edge(sourceSPBE1, SPBE.begin()->second, *fbb);
172 
173  const auto op = GET_NODE(GetPointerS<const gimple_cond>(last_stmt)->op0);
175  "---Condition operand (" + op->get_kind_text() + ") is " + op->ToString());
176  const auto cond_sn = GetPointer<const ssa_name>(op);
177  if(!cond_sn)
178  {
179  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Argument of cond expression is not a ssa");
180  continue;
181  }
182  const auto cond_defs = cond_sn->CGetDefStmts();
183  if(cond_defs.size() != 1)
184  {
186  "<--Condition variable is not defined in a single statement");
187  continue;
188  }
189  const auto cond_def = GET_NODE(*(cond_defs.begin()));
190  if(cond_def->get_kind() != gimple_assign_K)
191  {
192  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Condition not defined by gimple_assign");
193  continue;
194  }
195  const auto cond = GET_NODE(GetPointer<const gimple_assign>(cond_def)->op1);
196  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Condition variable is assigned in " + STR(cond));
197  if(cond->get_kind() != eq_expr_K && cond->get_kind() != ge_expr_K && cond->get_kind() != gt_expr_K &&
198  cond->get_kind() != le_expr_K && cond->get_kind() != lt_expr_K && cond->get_kind() != ne_expr_K &&
199  cond->get_kind() != uneq_expr_K and cond->get_kind() != ungt_expr_K && cond->get_kind() != unge_expr_K &&
200  cond->get_kind() != unle_expr_K && cond->get_kind() != unlt_expr_K)
201  {
202  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Condition is not a simple comparison");
203  continue;
204  }
206  const auto cond_be = GetPointerS<const binary_expr>(cond);
207  const auto first_operand = GET_NODE(cond_be->op0);
209  if(first_operand->get_kind() != ssa_name_K)
210  {
211  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--First operand of gimple cond is not ssa_name");
212  continue;
213  }
214  const auto sn = GetPointerS<const ssa_name>(first_operand);
216  const auto defs = sn->CGetDefStmts();
217  if(defs.size() != 1)
218  {
219  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Induction variable is not ssa");
220  continue;
221  }
222  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Induction variable is " + STR(first_operand));
223  const auto def = [&]() -> tree_nodeRef {
224  const auto temp_def = GET_NODE(*(defs.begin()));
225  if(do_while)
226  {
227  return temp_def;
228  }
229  const auto gp = GetPointer<const gimple_phi>(temp_def);
230  if(!gp)
231  {
232  return tree_nodeRef();
233  }
234  for(const auto& def_edge : gp->CGetDefEdgesList())
235  {
236  if(def_edge.second == sourceSPBE1_index)
237  {
238  const auto temp_sn = GetPointer<const ssa_name>(GET_NODE(def_edge.first));
239  if(!temp_sn)
240  {
241  return tree_nodeRef();
242  }
243  return GET_NODE(temp_sn->CGetDefStmt());
244  }
245  }
246  return tree_nodeRef();
247  }();
248  if(!def)
249  {
250  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Induction variable not assigned");
251  continue;
252  }
253  if(def->get_kind() != gimple_assign_K)
254  {
256  "<--Induction variable is assigned in " + def->ToString());
257  continue;
258  }
259  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Induction variable is assigned in " + def->ToString());
260  const auto ga = GetPointerS<const gimple_assign>(def);
261  if(GET_NODE(ga->op1)->get_kind() != plus_expr_K && GET_NODE(ga->op1)->get_kind() != minus_expr_K)
262  {
264  "<--Induction variable is not incremented or decremented");
265  continue;
266  }
267  const auto be = GetPointerS<const binary_expr>(GET_NODE(ga->op1));
268  if(GET_NODE(be->op1)->get_kind() != integer_cst_K)
269  {
271  "<--Induction variable is not incremented or decremented by a constant");
272  continue;
273  }
274  const auto second_induction_variable = GET_NODE(be->op0);
275  if(second_induction_variable->get_kind() != ssa_name_K)
276  {
277  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Temp induction variable is not a ssa");
278  continue;
279  }
280  const auto defs2 = GetPointerS<const ssa_name>(second_induction_variable)->CGetDefStmts();
281  if(defs2.size() != 1)
282  {
283  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Temp induction variable is not in ssa form");
284  continue;
285  }
286  const auto def2 = GET_NODE(*(defs2.begin()));
287  if(def2->get_kind() != gimple_phi_K)
288  {
289  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Temp induction variable is not defined in a phi");
290  continue;
291  }
292  const auto gp = GetPointerS<const gimple_phi>(def2);
293  if(gp->CGetDefEdgesList().size() != 2)
294  {
295  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Phi has not two incoming definitions");
296  continue;
297  }
298  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Init phi is " + gp->ToString());
299  const auto init = [&]() -> tree_nodeRef {
300  for(const auto& def_edge : gp->CGetDefEdgesList())
301  {
303  "---" + def_edge.first->ToString() + " comes from " + STR(def_edge.second));
304  if(def_edge.second != sourceSPBE1_index)
305  {
306  return def_edge.first;
307  }
308  }
309  return tree_nodeRef();
310  }();
311  loop->main_iv = first_operand->index;
312  loop->init = init;
313  loop->init_gimple_id = def2->index;
314  loop->inc_id = ga->index;
315  if(GET_NODE(be->op1)->get_kind() == integer_cst_K)
316  {
317  loop->increment = tree_helper::GetConstValue(be->op1);
318  if(be->get_kind() == minus_expr_K)
319  {
320  loop->increment = -loop->increment;
321  }
322  }
323  loop->upper_bound_tn = cond_be->op1;
324  loop->increment_tn = be->op1;
326  "---Comparison is " + STR(cond) + " (" + cond->get_kind_text() + ")");
327  if(GET_NODE(init)->get_kind() == integer_cst_K && GET_NODE(cond_be->op1)->get_kind() == integer_cst_K)
328  {
329  const auto cond_type = cond_be->get_kind();
330  loop->lower_bound = tree_helper::GetConstValue(init);
331  loop->upper_bound = tree_helper::GetConstValue(cond_be->op1);
332  if(cond_type == ge_expr_K || cond_type == le_expr_K || cond_type == unge_expr_K || cond_type == unle_expr_K)
333  {
335  loop->close_interval = true;
336  }
337  loop->loop_type |= COUNTABLE_LOOP;
338  }
339  if(init)
340  {
341  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Initialization " + init->ToString());
342  }
343  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Bound " + GET_NODE(loop->upper_bound_tn)->ToString());
345  "---Increment " + GET_NODE(loop->increment_tn)->ToString());
347  if(do_while && loop->is_innermost() && loop->num_blocks() == 1)
348  {
349  loop->loop_type |= PIPELINABLE_LOOP;
350  }
351 
352  return_value = DesignFlowStep_Status::SUCCESS;
353  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Analyzed loop " + STR(loop->GetId()));
354  }
355  if(parameters->getOption<bool>(OPT_print_dot))
356  {
357  function_behavior->CGetLoops()->WriteDot("LF.dot");
358  }
359  return return_value;
360 }
#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.
DesignFlowStep_Status InternalExec() override
Performs the loops analysis.
#define INDENT_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.
Step successfully executed.
#define GET_CLASS(obj)
Macro returning the actual type of an object.
Definition of the class representing a generic C application.
#define PIPELINABLE_LOOP
pipelinable loop
Definition: loop.hpp:141
RelationshipType
The relationship type.
Source must be executed to satisfy target.
#define COUNTABLE_LOOP
countable loop
Definition: loop.hpp:138
Data structure describing a basic block at tree level.
#define UNKNOWN_LOOP
unknown loop
Definition: loop.hpp:123
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 WHILE_LOOP
while or for loop
Definition: loop.hpp:126
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
LoopsAnalysisBambu(const ParameterConstRef _parameters, const application_managerRef AppM, unsigned int function_id, const DesignFlowManagerConstRef design_flow_manager)
Constructor.
Manager for pragma annotations.
Basic block control flow graph with feedback.
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
#define DEBUG_LEVEL_NONE
no debugging print is performed.
static bool has_omp_simd(const statement_list *sl)
Check if omp simd pragmas are present in given statement list.
~LoopsAnalysisBambu() override
Destructor.
This file collects some utility functions.
void init(int bucket[BUCKETSIZE])
Definition: sort.c:42
const unsigned int function_id
The index of the function to be analyzed.
#define DO_WHILE_LOOP
do while loop
Definition: loop.hpp:135
const application_managerRef AppM
The application manager.
Class specification of the tree_reindex support class.
Class specification of the basic_block structure.
interface of a loop
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
interface of loops finding algorithm
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.
refcount< tree_node > tree_nodeRef
RefCount type definition of the tree_node class structure.
Definition: tree_node.hpp:212
static integer_cst_t GetConstValue(const tree_nodeConstRef &tn, bool is_signed=true)
Get value from integer constant.
int debug_level
The debug level.
Class specification of the manager of the tree structures extracted from the raw file.
#define SINGLE_EXIT_LOOP
loop with single exit
Definition: loop.hpp:120
A brief description of the C++ Header File.
const FunctionBehaviorRef function_behavior
The function behavior of the function to be analyzed.
boost::graph_traits< graph >::edge_descriptor EdgeDescriptor
edge definition.
Definition: graph.hpp:1316

Generated on Mon Feb 12 2024 13:02:52 for PandA-2024.02 by doxygen 1.8.13