PandA-2024.02
storage_value_information.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  */
43 
45 #include "config_HAVE_ASSERTS.hpp"
46 
48 #include "function_behavior.hpp"
49 
51 #include "hls.hpp"
52 #include "hls_manager.hpp"
53 
55 #include "fu_binding.hpp"
56 
58 #include "Parameter.hpp"
59 #include "dbgPrintHelper.hpp" // for DEBUG_LEVEL_
60 #include "math_function.hpp"
61 #include "tree_helper.hpp"
62 #include "tree_manager.hpp"
63 #include "utility.hpp"
64 
65 StorageValueInformation::StorageValueInformation(const HLS_managerConstRef _HLS_mgr, const unsigned int _function_id)
66  : number_of_storage_values(0), HLS_mgr(_HLS_mgr), function_id(_function_id)
67 {
68 }
69 
71 
73 {
74  const hlsRef HLS = HLS_mgr->get_HLS(function_id);
75  const FunctionBehaviorConstRef FB = HLS_mgr->CGetFunctionBehavior(function_id);
77  fu = HLS->Rfu;
78  const tree_managerRef TreeM = HLS_mgr->get_tree_manager();
79 
81  VertexIterator ki, ki_end;
82  for(boost::tie(ki, ki_end) = boost::vertices(*data); ki != ki_end; ++ki)
83  {
84  const CustomSet<unsigned int>& scalar_defs = data->CGetOpNodeInfo(*ki)->GetVariables(
86  if(not scalar_defs.empty())
87  {
88  auto it_end = scalar_defs.end();
89 #if HAVE_ASSERTS
90  size_t counter = 0;
91 #endif
92  for(auto it = scalar_defs.begin(); it != it_end; ++it)
93  {
94  if(tree_helper::is_ssa_name(TreeM, *it) && !tree_helper::is_virtual(TreeM, *it) &&
95  !tree_helper::is_parameter(TreeM, *it))
96  {
97  HLS->storage_value_information->vw2vertex[*it] = *ki;
98 #if HAVE_ASSERTS
99  ++counter;
100 #endif
101  }
102  }
103 #if HAVE_ASSERTS
104  if(counter > 1 and not(GET_TYPE(data, *ki) & TYPE_ENTRY))
105  {
106  INDENT_DBG_MEX(DEBUG_LEVEL_NONE, 0, GET_NAME(data, *ki) + " defines:");
107  for(const auto scalar_def : scalar_defs)
108  {
109  if(tree_helper::is_ssa_name(TreeM, scalar_def) and not tree_helper::is_virtual(TreeM, scalar_def) and
110  not tree_helper::is_parameter(TreeM, scalar_def))
111  {
112  INDENT_DBG_MEX(DEBUG_LEVEL_NONE, 0, STR(TreeM->CGetTreeNode(scalar_def)));
113  }
114  }
115  THROW_UNREACHABLE("More than one definition");
116  }
117 #endif
118  }
119  }
120 }
121 
123 {
125 }
126 
127 unsigned int StorageValueInformation::get_variable_index(unsigned int storage_value_index) const
128 {
129  THROW_ASSERT(variable_index_map.find(storage_value_index) != variable_index_map.end(),
130  "the storage value is missing");
131  return variable_index_map.find(storage_value_index)->second;
132 }
133 
134 int StorageValueInformation::get_compatibility_weight(unsigned int storage_value_index1,
135  unsigned int storage_value_index2) const
136 {
137  unsigned int var1 = get_variable_index(storage_value_index1);
138  unsigned int var2 = get_variable_index(storage_value_index2);
139 #if 0
140  if(vw2vertex.find(var1) == vw2vertex.end())
141  {
142  //std::cerr << var1 << std::endl;
143  return 1;
144  }
145 #endif
146  THROW_ASSERT(vw2vertex.find(var1) != vw2vertex.end(), "variable not in the map " + STR(var1));
147  THROW_ASSERT(vw2vertex.find(var2) != vw2vertex.end(),
148  "variable " + STR(HLS_mgr->get_tree_manager()->CGetTreeNode(var2)) + " not in the map");
149  vertex v1 = vw2vertex.find(var1)->second;
150  bool is_a_phi1 = (GET_TYPE(data, v1) & TYPE_PHI) != 0;
151  vertex v2 = vw2vertex.find(var2)->second;
152  bool is_a_phi2 = (GET_TYPE(data, v2) & TYPE_PHI) != 0;
153 
154  // compute the successors of v1 e v2
156  "-->Evaluation storage values (vars): [" + STR(HLS_mgr->get_tree_manager()->CGetTreeNode(var1)) +
157  "]"
158  " and [" +
159  STR(HLS_mgr->get_tree_manager()->CGetTreeNode(var2)) + "]");
161  "---vertex names: [" + GET_NAME(data, v1) +
162  "]"
163  " and [" +
164  GET_NAME(data, v2) + "]");
165 
166  const auto it_succ_v1 = boost::adjacent_vertices(v1, *data);
167  const auto it_succ_v2 = boost::adjacent_vertices(v2, *data);
168 
170  if(HLS_mgr->get_parameter()->getOption<bool>(OPT_shared_input_registers))
171  {
172  static const std::vector<std::string> labels = {"mult_expr", "widen_mult_expr", "ternary_plus_expr",
173  "ternary_mm_expr", "ternary_pm_expr", "ternary_mp_expr"};
174  for(const auto& label : labels)
175  {
176  // check if v1 or v2 drive complex operations
177  // variable coming from the Entry vertex have to be neglected in this analysis
178  CustomOrderedSet<unsigned int> op_succ_of_v1_port0, op_succ_of_v1_port1, op_succ_of_v1_port2;
179  if(!(GET_TYPE(data, v1) & TYPE_ENTRY))
180  {
181  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, 0, "-->Statement with USE first variable");
182  std::for_each(it_succ_v1.first, it_succ_v1.second,
183  [this, &op_succ_of_v1_port0, &op_succ_of_v1_port1, &op_succ_of_v1_port2, &var1,
184  &label](const vertex succ) {
185  const std::string op_label = data->CGetOpNodeInfo(succ)->GetOperation();
186  const unsigned int succ_id = data->CGetOpNodeInfo(succ)->GetNodeId();
187  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, 0,
188  "---[" + STR(succ_id) + "] type: " + STR(op_label));
189  if((op_label == label))
190  {
191  std::vector<HLS_manager::io_binding_type> var_read =
192  HLS_mgr->get_required_values(function_id, succ);
193  if(std::get<0>(var_read[0]) == var1)
194  {
195  op_succ_of_v1_port0.insert(succ_id);
196  }
197  else if(std::get<0>(var_read[1]) == var1)
198  {
199  op_succ_of_v1_port1.insert(succ_id);
200  }
201  else if(var_read.size() == 3 && std::get<0>(var_read[2]) == var1)
202  {
203  op_succ_of_v1_port2.insert(succ_id);
204  }
205  else
206  {
207  THROW_ERROR("unexpected case:" + STR(succ_id) + "|" + STR(std::get<0>(var_read[0])) +
208  ":" + STR(std::get<0>(var_read[1])));
209  }
210  }
211  });
213  }
214 
215  CustomOrderedSet<unsigned int> op_succ_of_v2_port0, op_succ_of_v2_port1, op_succ_of_v2_port2;
216  if(!(GET_TYPE(data, v2) & TYPE_ENTRY))
217  {
218  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, 0, "-->Statement with USE second variable");
219  std::for_each(it_succ_v2.first, it_succ_v2.second,
220  [this, &op_succ_of_v2_port0, &op_succ_of_v2_port1, &op_succ_of_v2_port2, &var2,
221  &label](const vertex succ) {
222  const std::string op_label = data->CGetOpNodeInfo(succ)->GetOperation();
223  const unsigned int succ_id = data->CGetOpNodeInfo(succ)->GetNodeId();
224  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, 0,
225  "---[" + STR(succ_id) + "] type: " + STR(op_label));
226  if(op_label == label)
227  {
228  std::vector<HLS_manager::io_binding_type> var_read =
229  HLS_mgr->get_required_values(function_id, succ);
230  if(std::get<0>(var_read[0]) == var2)
231  {
232  op_succ_of_v2_port0.insert(succ_id);
233  }
234  else if(std::get<0>(var_read[1]) == var2)
235  {
236  op_succ_of_v2_port1.insert(succ_id);
237  }
238  else if(var_read.size() == 3 && std::get<0>(var_read[2]) == var2)
239  {
240  op_succ_of_v2_port2.insert(succ_id);
241  }
242  else
243  {
244  THROW_ERROR("unexpected case");
245  }
246  }
247  });
249  }
250 
251  // Check if both pilot complex operations
252  auto P0cond = !op_succ_of_v1_port0.empty() && !op_succ_of_v2_port0.empty();
253  auto P1cond = (!op_succ_of_v1_port1.empty() && !op_succ_of_v2_port1.empty());
254  auto P2cond = (!op_succ_of_v1_port2.empty() && !op_succ_of_v2_port2.empty());
255  const bool both_pilot_complex_ops = P0cond || P1cond || P2cond;
256 
257  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, 0, "Both pilot a complex operation: " + STR(both_pilot_complex_ops));
258  if(both_pilot_complex_ops)
259  {
261  if(P0cond)
262  {
263  return 6;
264  }
265  else if(P1cond)
266  {
267  return 7;
268  }
269  else if(P2cond)
270  {
271  return 8;
272  }
273  else
274  {
275  THROW_ERROR("unexpected condition");
276  }
277  }
278  }
279  }
281  // ------------
282 
283  const CustomSet<unsigned int>& ssa_read1 = data->CGetOpNodeInfo(v1)->GetVariables(
285  if(is_a_phi1)
286  {
287  if(ssa_read1.find(var2) != ssa_read1.end())
288  {
289  return 5;
290  }
291  }
292  const CustomSet<unsigned int>& ssa_read2 = data->CGetOpNodeInfo(v2)->GetVariables(
294  if(is_a_phi2)
295  {
296  if(ssa_read2.find(var1) != ssa_read2.end())
297  {
298  return 5;
299  }
300  }
301  if(fu.lock())
302  {
303  unsigned int fu_unit1 = fu.lock()->get_assign(v1);
304  unsigned int fu_unit2 = fu.lock()->get_assign(v2);
305  if(fu_unit1 == fu_unit2)
306  {
307  if(fu.lock()->get_index(v1) != INFINITE_UINT)
308  {
309  /*unsigned int base_index1= tree_helper::get_base_index(HLSMgr->get_tree_manager(), var1);
310  unsigned int base_index2= tree_helper::get_base_index(HLSMgr->get_tree_manager(), var2);*/
311  if(fu.lock()->get_index(v1) == fu.lock()->get_index(v2) /* || base_index1 == base_index2*/)
312  {
313  return 5;
314  }
315  else
316  {
317  return 1;
318  }
319  }
320  bool they_have_common_inputs = false;
321  auto it1_end = ssa_read1.end();
322  for(auto it1 = ssa_read1.begin(); it1 != it1_end; ++it1)
323  {
324  if(ssa_read2.find(*it1) != ssa_read2.end())
325  {
326  they_have_common_inputs = true;
327  break;
328  }
329  else if(vw2vertex.find(*it1) != vw2vertex.end())
330  {
331  vertex from_v1 = vw2vertex.find(*it1)->second;
332  auto it2_end = ssa_read2.end();
333  for(auto it2 = ssa_read2.begin(); it2 != it2_end; ++it2)
334  {
335  if(vw2vertex.find(*it2) != vw2vertex.end())
336  {
337  vertex from_v2 = vw2vertex.find(*it2)->second;
338  if(fu.lock()->get_assign(from_v1) == fu.lock()->get_assign(from_v2) &&
339  fu.lock()->get_index(from_v1) != INFINITE_UINT &&
340  fu.lock()->get_index(from_v1) == fu.lock()->get_index(from_v2))
341  {
342  they_have_common_inputs = true;
343  break;
344  }
345  }
346  }
347  if(they_have_common_inputs)
348  {
349  break;
350  }
351  }
352  }
353  if(they_have_common_inputs)
354  {
355  return 4;
356  }
357  if(ssa_read1.find(var2) != ssa_read1.end())
358  {
359  return 3;
360  }
361  if(ssa_read2.find(var1) != ssa_read2.end())
362  {
363  return 3;
364  }
365  return 2;
366  }
367  }
368  return 1;
369 }
370 
371 bool StorageValueInformation::are_value_bitsize_compatible(unsigned int storage_value_index1,
372  unsigned int storage_value_index2) const
373 {
374  const auto var1_nid = get_variable_index(storage_value_index1);
375  const auto var2_nid = get_variable_index(storage_value_index2);
376  const auto TM = HLS_mgr->get_tree_manager();
377  const auto var1 = TM->CGetTreeReindex(var1_nid);
378  const auto var2 = TM->CGetTreeReindex(var2_nid);
379  const auto isInt1 = tree_helper::IsSignedIntegerType(var1);
380  const auto isInt2 = tree_helper::IsSignedIntegerType(var2);
381  const auto isReal1 = tree_helper::IsRealType(var1);
382  const auto isReal2 = tree_helper::IsRealType(var2);
383  const auto size1 = tree_helper::Size(var1);
384  const auto size2 = tree_helper::Size(var2);
385  return isInt1 == isInt2 && isReal1 == isReal2 &&
386  (((isInt1 && isInt2) || (isReal1 && isReal2)) ? size1 == size2 : ceil_pow2(size1) == ceil_pow2(size2));
387 }
int get_compatibility_weight(unsigned int storage_value_index1, unsigned int storage_value_index2) const
return a weight that estimate how much two storage values are compatible.
Wrefcount< const fu_binding > fu
functional unit assignments
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
unsigned int get_variable_index(unsigned int storage_value_index) const
Returns the index of the variable associated with the storage value in a given vertex.
Data structure representing the entire HLS information.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
#define GET_TYPE(data, vertex_index)
Helper macro returning the type associated with a node.
File containing functions and utilities to support the printing of debug messagges.
const HLS_managerConstRef HLS_mgr
The HLS manager.
CustomUnorderedMap< unsigned int, vertex > vw2vertex
relation between var written and operations
mathematical utility function not provided by standard libraries
#define GET_NAME(data, vertex_index)
Helper macro returning the name associated with a node.
static bool is_parameter(const tree_managerConstRef &TM, const unsigned int index)
return true in case the index corresponds to a parameter in ssa form or not
const tree_nodeConstRef CGetTreeNode(const unsigned int i) const
OpGraphConstRef data
operation graph used to compute the affinity between storage values
#define TYPE_PHI
constant string identifying an operation node of type PHI
Definition: op_graph.hpp:135
#define STR(s)
Macro which performs a lexical_cast to a string.
bool are_value_bitsize_compatible(unsigned int storage_value_index1, unsigned int storage_value_index2) const
return the in case the storage values have compatible size
static bool IsSignedIntegerType(const tree_nodeConstRef &type)
Return true if the treenode is of integer type.
const OpNodeInfoConstRef CGetOpNodeInfo(const vertex node) const
Returns the info associated with a node.
Definition: op_graph.hpp:843
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
fu_bindingRef Rfu
Store the refcounted functional unit binding of the operations.
Definition: hls.hpp:121
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
StorageValueInformationRef storage_value_information
data-structure for storage values
Definition: hls.hpp:130
static bool is_virtual(const tree_managerConstRef &TM, const unsigned int index)
return true in case the ssa_name is virtual
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
boost::graph_traits< graph >::vertex_iterator VertexIterator
vertex_iterator definition.
Definition: graph.hpp:1307
const unsigned int function_id
The index of the function.
This file collects some utility functions and macros.
#define DEBUG_LEVEL_NONE
no debugging print is performed.
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
StorageValueInformation(const HLS_managerConstRef HLS_mgr, const unsigned int function_id)
Constructor.
This package is used to define the storage value scheme adopted by the register allocation algorithms...
This file collects some utility functions.
static bool is_ssa_name(const tree_managerConstRef &TM, const unsigned int index)
Return true in case index is a ssa_name.
refcount< T > lock() const
Definition: refcount.hpp:212
void Initialize()
Initialize the step (i.e., like a constructor)
Data structure used to store the functional-unit binding of the vertexes.
const OpGraphConstRef CGetOpGraph(FunctionBehavior::graph_type gt) const
This method returns the operation graphs.
#define INFINITE_UINT
UNSIGNED INT representing infinite.
Definition: utility.hpp:70
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
virtual ~StorageValueInformation()
Destructor.
this class is used to manage the command-line or XML options.
#define TYPE_ENTRY
constant identifying the node type of an entry node.
unsigned counter[N_THREADS]
Definition: data.c:3
unsigned int get_number_of_storage_values() const
Returns the number of storage values inserted.
CustomUnorderedMap< unsigned int, unsigned int > variable_index_map
put into relation storage value index with variables
Data structure definition for high-level synthesis flow.
Class specification of the manager of the tree structures extracted from the raw file.
A brief description of the C++ Header File.
static bool IsRealType(const tree_nodeConstRef &type)
Return true if the treenode is of real type.
unsigned int number_of_storage_values
current number of storage values
#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:53 for PandA-2024.02 by doxygen 1.8.13