PandA-2024.02
reg_binding.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 "reg_binding.hpp"
45 #include "Parameter.hpp"
46 #include "behavioral_helper.hpp"
47 #include "custom_set.hpp"
48 #include "dbgPrintHelper.hpp" // for DEBUG_LEVEL_
49 #include "function_behavior.hpp"
50 #include "generic_obj.hpp"
51 #include "hls.hpp"
52 #include "hls_device.hpp"
53 #include "hls_manager.hpp"
54 #include "liveness.hpp"
55 #include "omp_functions.hpp"
56 #include "reg_binding_cs.hpp"
57 #include "register_obj.hpp"
61 #include "structural_manager.hpp"
62 #include "technology_manager.hpp"
63 #include "technology_node.hpp"
64 #include <list>
65 #include <utility>
66 
67 std::string reg_binding::reset_type;
68 
69 reg_binding::reg_binding(const hlsRef& HLS_, const HLS_managerRef HLSMgr_)
70  : debug(HLS_->debug_level),
71  used_regs(0),
72  HLS(HLS_),
73  HLSMgr(HLSMgr_),
74  all_regs_without_enable(false),
75  FB(HLSMgr->CGetFunctionBehavior(HLS->functionId))
76 {
77  if(reset_type.empty())
78  {
79  reset_type = HLSMgr->get_parameter()->getOption<std::string>(OPT_reset_type);
80  }
81 }
82 
83 reg_binding::~reg_binding() = default;
84 
86 {
87  if(HLS->Param->isOption(OPT_context_switch))
88  {
89  auto omp_functions = GetPointer<OmpFunctions>(HLSMgr_->Rfuns);
90  bool found = false;
91  if(HLSMgr_->is_reading_writing_function(HLS->functionId) &&
92  omp_functions->kernel_functions.find(HLS->functionId) != omp_functions->kernel_functions.end())
93  {
94  found = true;
95  }
96  if(HLSMgr_->is_reading_writing_function(HLS->functionId) &&
97  omp_functions->parallelized_functions.find(HLS->functionId) != omp_functions->parallelized_functions.end())
98  {
99  found = true;
100  }
101  if(omp_functions->atomic_functions.find(HLS->functionId) != omp_functions->atomic_functions.end())
102  {
103  found = true;
104  }
105  if(found)
106  {
107  return reg_bindingRef(new reg_binding_cs(HLS, HLSMgr_));
108  }
109  }
110  return reg_bindingRef(new reg_binding(HLS, HLSMgr_));
111 }
112 
113 void reg_binding::print_el(const_iterator& it) const
114 {
117  "---Storage Value: " + STR(it->first) + " for variable " +
118  FB->CGetBehavioralHelper()->PrintVariable(HLS->storage_value_information->get_variable_index(it->first)) +
119  " stored into register " + it->second->get_string());
120 }
121 
123 {
125  THROW_ASSERT(reg2storage_values.count(r) && reg2storage_values.at(r).size(),
126  "at least a storage value has to be mapped on register r");
127 
128  for(const auto rs : reg2storage_values.at(r))
129  {
131  }
132  return vars;
133 }
134 
135 unsigned long long reg_binding::compute_bitsize(unsigned int r)
136 {
137  const auto reg_vars = get_vars(r);
138  unsigned long long max_bits = 0;
139  for(const auto reg_var : reg_vars)
140  {
141  structural_type_descriptor node_type0(reg_var, FB->CGetBehavioralHelper());
142  auto node_size = STD_GET_SIZE(&node_type0);
144  "- Analyzing node " + STR(reg_var) + ", whose type is " + node_type0.get_name() +
145  " (size: " + STR(node_type0.size) + ", vector_size: " + STR(node_type0.vector_size) + ")");
146  max_bits = max_bits < node_size ? node_size : max_bits;
147  }
148  bitsize_map[r] = max_bits;
149  return max_bits;
150 }
151 
152 unsigned long long reg_binding::get_bitsize(unsigned int r) const
153 {
154  THROW_ASSERT(bitsize_map.count(r), "register bitsize not computed");
155  return bitsize_map.at(r);
156 }
157 
159 {
160  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, HLS->debug_level, "Specializing " + reg->get_path() + ":");
161  const auto reg_m = GetPointerS<module>(reg);
162  const auto& in_type = reg_m->get_in_port(0)->get_typeRef();
163  const auto& out_type = reg_m->get_out_port(0)->get_typeRef();
164  const auto bits = compute_bitsize(r);
165  const auto max_bits = std::max({bits, STD_GET_SIZE(in_type), STD_GET_SIZE(out_type)});
166  const auto offset = static_cast<unsigned int>(reg_m->get_in_port(0U)->get_id() == CLOCK_PORT_NAME) +
167  static_cast<unsigned int>(reg_m->get_in_port(1U)->get_id() == RESET_PORT_NAME);
168 
169  if(STD_GET_SIZE(in_type) < max_bits)
170  {
171  reg_m->get_in_port(offset)->type_resize(max_bits); // in1
173  "- " + reg_m->get_in_port(offset)->get_path() + " -> " + in_type->get_name() +
174  " (size: " + STR(in_type->size) + ", vector_size: " + STR(in_type->vector_size) + ")");
175  }
176  if(STD_GET_SIZE(out_type) < max_bits)
177  {
178  reg_m->get_out_port(0)->type_resize(max_bits); // out1
180  "- " + reg_m->get_out_port(0)->get_path() + " -> " + out_type->get_name() +
181  " (size: " + STR(out_type->size) + ", vector_size: " + STR(out_type->vector_size) + ")");
182  }
183 }
184 
186 {
187  std::map<unsigned int, unsigned int> n_in;
188  std::map<unsigned int, unsigned int> n_out;
189  for(const auto v : HLS->Rliv->get_support())
190  {
191  const auto dummy_offset = HLS->Rliv->is_a_dummy_state(v) ? 1U : 0U;
192  const auto& live_in = HLS->Rliv->get_live_in(v);
193  for(const auto li : live_in)
194  {
195  if(n_in.find(li) == n_in.end())
196  {
197  n_in[li] = 1U + dummy_offset;
198  }
199  else
200  {
201  n_in[li] = n_in[li] + 1U + dummy_offset;
202  }
203  }
204  const auto& live_out = HLS->Rliv->get_live_out(v);
205  for(const auto lo : live_out)
206  {
207  if(!n_out.count(lo))
208  {
209  n_out[lo] = 1 + dummy_offset;
210  if(live_in.count(lo))
211  {
212  n_out[lo] = 2 + dummy_offset;
213  }
214  }
215  else
216  {
217  n_out[lo] = n_out[lo] + 1 + dummy_offset;
218  }
219  }
220  }
221 
222  for(auto i = 0U; i < get_used_regs(); i++)
223  {
224  const auto all_woe = [&]() {
225  const auto store_vars_set = get_vars(i);
226  for(const auto sv : store_vars_set)
227  {
228  if(n_in.find(sv) == n_in.end() || n_in.find(sv)->second != 1 || n_out.find(sv) == n_out.end() ||
229  n_out.find(sv)->second != 1)
230  {
231  return false;
232  }
233  }
234  return true;
235  }();
236  if(all_woe)
237  {
238  is_without_enable.insert(i);
239  }
240  }
241 }
242 
243 void reg_binding::bind(unsigned int sv, unsigned int index)
244 {
245  reverse_map[sv] = index;
246  if(!unique_table.count(index))
247  {
249  if(HLSMgr->GetFunctionBehavior(HLS->functionId)->is_simple_pipeline())
250  {
251  for(const auto v : HLS->Rliv->get_support())
252  {
253  if(HLS->STG->GetStg()->GetStateInfo(v)->loopId != 0)
254  {
255  auto live_in = HLS->Rliv->get_live_in(v);
256  for(unsigned int var : live_in)
257  {
259  {
261  }
262  }
263  }
264  }
265  }
266  }
267  auto i = this->find(sv);
268  if(i == this->end())
269  {
270  this->insert(std::make_pair(sv, unique_table[index]));
271  }
272  else
273  {
274  i->second = unique_table[index];
275  }
276  reg2storage_values[index].insert(sv);
277 }
278 
279 const register_obj& reg_binding::operator[](unsigned int v)
280 {
281  THROW_ASSERT(count(v), "variable not preset");
282  return *GetPointerS<register_obj>(at(v));
283 }
284 
286 {
287  const auto& SM = HLS->datapath;
288  const auto& circuit = SM->get_circ();
289 
290  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug, "reg_binding::add_registers - Start");
291 
292  const auto stallable_pipeline = FB->is_pipeline_enabled() && !FB->is_simple_pipeline();
293  if(stallable_pipeline)
294  {
296  "Number of registers: " + STR(get_used_regs() + stall_reg_table.size()) + ", " +
297  STR(stall_reg_table.size()) + " introduced for supporting pipelined loops");
298  }
299  else
300  {
301  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug, "Number of registers: " + STR(get_used_regs()));
302 
303  // all registers need an enable in stallable pipelines
305  }
308  for(auto i = 0U; i < get_used_regs(); ++i)
309  {
310  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug, "Allocating register number: " + STR(i));
311  generic_objRef regis = get(i);
312  auto name = regis->get_string();
313  const auto curr_is_is_without_enable = is_without_enable.count(i);
314  all_regs_without_enable = all_regs_without_enable && curr_is_is_without_enable;
315  const auto register_type_name = GetRegisterFUName(i);
316  const auto library = HLS->HLS_D->get_technology_manager()->get_library(register_type_name);
317  auto reg_mod = SM->add_module_from_technology_library(name, register_type_name, library, circuit,
318  HLS->HLS_D->get_technology_manager());
319  specialise_reg(reg_mod, i);
320  auto port_ck = reg_mod->find_member(CLOCK_PORT_NAME, port_o_K, reg_mod);
321  THROW_ASSERT(port_ck, "Clock port missing from register.");
322  SM->add_connection(clock_port, port_ck);
323  auto port_rst = reg_mod->find_member(RESET_PORT_NAME, port_o_K, reg_mod);
324  if(port_rst)
325  {
326  SM->add_connection(reset_port, port_rst);
327  }
328  regis->set_structural_obj(reg_mod);
329  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug, "Register " + STR(i) + " successfully allocated");
330  if(stallable_pipeline && stall_reg_table.count(i))
331  {
333  "Register " + STR(i) + " also needs a stall register, allocating it...");
334  name = "stall_" + name;
335  reg_mod = SM->add_module_from_technology_library(name, register_type_name, library, circuit,
336  HLS->HLS_D->get_technology_manager());
337  specialise_reg(reg_mod, i);
338  port_ck = reg_mod->find_member(CLOCK_PORT_NAME, port_o_K, reg_mod);
339  SM->add_connection(clock_port, port_ck);
340  port_rst = reg_mod->find_member(RESET_PORT_NAME, port_o_K, reg_mod);
341  THROW_ASSERT(port_rst != nullptr, "The stall register was not allocated a reset port");
342  SM->add_connection(reset_port, port_rst);
343  regis->set_structural_obj(reg_mod);
344  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug, "Successfully allocated stall register for std reg " + STR(i));
345  }
346  }
347  PRINT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug, "reg_binding::add_registers - End");
349  {
350  auto number_ff = 0ull;
351  for(auto r = 0U; r < get_used_regs(); r++)
352  {
353  number_ff += get_bitsize(r);
354  }
356  "---Total number of flip-flops in function " + FB->CGetBehavioralHelper()->get_function_name() +
357  ": " + STR(number_ff));
358  }
360  {
362  "---All registers are without enable: function pipelining may come for free");
363  }
364 }
365 
366 std::string reg_binding::GetRegisterFUName(unsigned int i)
367 {
368  if(is_without_enable.count(i) || FB->is_simple_pipeline())
369  {
370  return register_STD;
371  }
372  else if(reset_type == "no")
373  {
374  return register_SE;
375  }
376  else if(reset_type == "sync")
377  {
378  return register_SRSE;
379  }
380  return register_SARSE;
381 }
Class specification to contain liveness information.
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
unsigned long long compute_bitsize(unsigned int r)
return and set the bitsize associated with given register
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.
~reg_binding() override
Destructor.
std::map< unsigned int, generic_objRef > stall_reg_table
map between std register index and stall register object for pipelines
Definition: reg_binding.hpp:88
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;.
refcount< reg_binding > reg_bindingRef
RefCount type definition of the reg_binding class structure.
structural_managerRef datapath
Store the datapath description.
Definition: hls.hpp:155
This file contains the structures needed to manage a graph that will represent the state transition g...
Structure representing the most relevant information about the type of a structural object...
const ParameterConstRef Param
class containing all the parameters
Definition: hls.hpp:169
CustomOrderedSet< unsigned int > get_vars(const unsigned int &r) const
Returns the set of variable associated with the register.
const structural_objectRef get_circ() const
Get a reference to circ field.
bool all_regs_without_enable
when true all registers do not require write enable: pipelining comes for free
bool is_a_dummy_state(vertex state)
check if a state is a dummy state
Definition: liveness.hpp:396
const FunctionBehaviorConstRef FB
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
std::map< unsigned int, unsigned long long > bitsize_map
relation between registers and their bitsize
Definition: reg_binding.hpp:94
const HLS_deviceRef HLS_D
reference to the information representing the target for the synthesis
Definition: hls.hpp:107
void bind(unsigned int sv, unsigned int index)
class modeling a register object
void insert(node_tree **tree, int val)
Definition: tree.c:121
std::map< unsigned int, generic_objRef > unique_table
map between register index and object
Definition: reg_binding.hpp:85
reg_binding(const hlsRef &HLS, const HLS_managerRef HLSMgr_)
Constructor.
Definition: reg_binding.cpp:69
void set_structural_obj(const structural_objectRef &SM_)
Sets structural_object associated to this object.
Class specification of the manager of the technology library data structures.
#define OUTPUT_LEVEL_MINIMUM
minimum debugging print is performed.
hlsRef HLS
HLS data-structure.
Definition: reg_binding.hpp:97
#define STR(s)
Macro which performs a lexical_cast to a string.
const register_obj & operator[](unsigned int v)
redefinition of the [] operator
#define max
Definition: backprop.h:17
static std::string reset_type
static reg_bindingRef create_reg_binding(const hlsRef &HLS, const HLS_managerRef HLSMgr_)
Definition: reg_binding.cpp:85
Base class for all resources into datapath.
#define CLOCK_PORT_NAME
standard name for ports
unsigned long long get_bitsize(unsigned int r) const
return bitsize
const std::list< vertex > & get_support() const
return the support set of the live in/out
Definition: liveness.hpp:212
const std::string get_string() const
Returns the name associated with the element.
Data structure used to store the register binding of variables.
StorageValueInformationRef storage_value_information
data-structure for storage values
Definition: hls.hpp:130
const HLS_managerRef HLSMgr
information about all the HLS synthesis
std::map< unsigned int, CustomOrderedSet< unsigned int > > reg2storage_values
map between the register and the associated storage value
Class specification of the data structures used to manage technology information. ...
const std::string get_path() const
Return a unique identifier of the structural object.
int output_level
verbosity level of the class
Definition: hls.hpp:175
#define index(x, y)
Definition: Keccak.c:74
redefinition of set to manage ordered/unordered structures
Base class for all register into datapath.
unsigned offset[NUM_VERTICES+1]
Definition: graph.h:3
This file contains the structures needed to manage a graph that will represent the state transition g...
const CustomOrderedSet< unsigned int > & get_live_out(const vertex &v) const
Get the set of variables live at the output of a vertex.
Definition: liveness.cpp:142
virtual void specialise_reg(structural_objectRef &reg, unsigned int r)
Specialise a register according to the type of the variables crossing it.
int debug
level of the verbosity during the debugging
Definition: reg_binding.hpp:79
This package is used to define the storage value scheme adopted by the register allocation algorithms...
livenessRef Rliv
data-structure containing the variable liveness
Definition: hls.hpp:127
#define register_STD
simple register without reset
#define OUTPUT_LEVEL_VERY_PEDANTIC
verbose debugging print is performed.
virtual std::string GetRegisterFUName(unsigned int i)
return the name of register to be used
virtual unsigned int get_storage_value_index(vertex curr_vertex, unsigned int var_index)=0
Returns the index of the storage value associated with the variable in a given vertex.
#define register_SARSE
register with synchronized asynchronous reset and synchronous enable
unsigned int get_used_regs() const
returns number of used register
void compute_is_without_enable()
compute the is with out enable relation
virtual void add_to_SM(structural_objectRef clock_port, structural_objectRef reset_port)
Add the resulting registers to the structural description of the datapath.
this class is used to manage the command-line or XML options.
#define register_SRSE
register with synchronous reset and synchronous enable
CustomOrderedSet< unsigned int > is_without_enable
store the set of register without enable
StateTransitionGraphRef GetStg()
Returns pointer to state transition graph created.
unsigned int functionId
this is the identifier of the function to be implemented
Definition: hls.hpp:87
#define RESET_PORT_NAME
Class implementation of the structural_manager.
StateTransitionGraphManagerRef STG
Store the refcounted state transition graph.
Definition: hls.hpp:124
void print_el(const_iterator &it) const override
Function that print the register binding associated with a storage value.
#define register_SE
register with synchronous enable
Datastructure to describe functions allocation in high-level synthesis.
unsigned int used_regs
number of used register
Definition: reg_binding.hpp:82
Data structure definition for high-level synthesis flow.
int debug_level
debugging level of the class
Definition: hls.hpp:172
std::map< unsigned int, unsigned int > reverse_map
bind the storage value with the register instance
Definition: reg_binding.hpp:91
refcount< generic_obj > generic_objRef
RefCount definition for generic_obj class.
HLS specialization of generic_device.
A brief description of the C++ Header File.
const CustomOrderedSet< unsigned int > & get_live_in(const vertex &v) const
Get the set of variables live at the input of a vertex.
Definition: liveness.cpp:109
#define STD_GET_SIZE(structural_obj)
Macro returning the size of a type.
#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