PandA-2024.02
hls_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  */
43 #include "hls_manager.hpp"
44 
45 #include "BackendFlow.hpp"
46 #include "Parameter.hpp"
47 #include "behavioral_helper.hpp"
48 #include "call_graph_manager.hpp"
49 #include "ext_tree_node.hpp"
50 #include "function_behavior.hpp"
51 #include "hls.hpp"
52 #include "hls_constraints.hpp"
53 #include "hls_device.hpp"
54 #include "memory.hpp"
55 #include "op_graph.hpp"
56 #include "polixml.hpp"
57 #include "tree_helper.hpp"
58 #include "tree_manager.hpp"
59 #include "tree_reindex.hpp"
60 #include "utility.hpp"
61 #include "xml_dom_parser.hpp"
62 #include "xml_helper.hpp"
63 
64 #if HAVE_TASTE
65 #include "aadl_information.hpp"
66 #include "functions.hpp"
67 #endif
68 #define MAX_BITWIDTH_SIZE 4096
69 
70 #if defined(__clang__)
71 #pragma clang diagnostic push
72 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
73 #pragma clang diagnostic ignored "-Wsign-conversion"
74 #pragma clang diagnostic ignored "-Wswitch-enum"
75 #else
76 #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
77 #pragma GCC diagnostic ignored "-Wsign-conversion"
78 #pragma GCC diagnostic ignored "-Wswitch-enum"
79 #endif
80 
81 #define PUGIXML_HEADER_ONLY
82 #include <pugixml.hpp>
83 
84 #if defined(__clang__)
85 #pragma clang diagnostic pop
86 #else
87 #pragma GCC diagnostic pop
88 #endif
89 
91  : application_manager(FunctionExpanderConstRef(new FunctionExpander()), false, _Param),
92  HLS_D(_HLS_D),
93  memory_version(1),
94  base_address(0),
95  HLS_execution_time(0)
96 #if HAVE_TASTE
97  ,
98  aadl_information(new AadlInformation())
99 #endif
100 {
101 #if HAVE_TASTE
102  if(Param->isOption(OPT_context_switch))
103  {
104  ;
105  }
106  else
107  {
108  Rfuns = functionsRef(new functions());
109  }
110 #endif
111 }
112 
113 HLS_manager::~HLS_manager() = default;
114 
115 hlsRef HLS_manager::get_HLS(unsigned int funId) const
116 {
117  if(!funId)
118  {
119  return hlsRef();
120  }
121  if(hlsMap.find(funId) == hlsMap.end())
122  {
123  return hlsRef();
124  }
125  return hlsMap.find(funId)->second;
126 }
127 
129 {
130  return HLS_D;
131 }
132 
133 hlsRef HLS_manager::create_HLS(const HLS_managerRef HLSMgr, unsigned int functionId)
134 {
135  THROW_ASSERT(functionId, "No function");
136  const std::deque<vertex>& OperationsList = HLSMgr->CGetFunctionBehavior(functionId)->get_levels();
137  OpVertexSet Operations(HLSMgr->CGetFunctionBehavior(functionId)->CGetOpGraph(FunctionBehavior::CFG));
138  Operations.insert(OperationsList.begin(), OperationsList.end());
139  if(HLSMgr->hlsMap.find(functionId) == HLSMgr->hlsMap.end())
140  {
142  const std::string function_name = tree_helper::name_function(HLSMgr->get_tree_manager(), functionId);
143  HLS_constraintsRef HLS_C = HLS_constraintsRef(new HLS_constraints(HLSMgr->get_parameter(), function_name));
144  for(const auto& globalRC : HLSMgr->global_resource_constraints)
145  {
146  if(HLS_C->get_number_fu(globalRC.first.first, globalRC.first.second) == INFINITE_UINT)
147  {
148  HLS_C->set_number_fu(globalRC.first.first, globalRC.first.second, globalRC.second.first);
149  }
150  }
151  HLSMgr->hlsMap[functionId] =
152  hlsRef(new hls(HLSMgr->get_parameter(), functionId, Operations, HLSMgr->get_HLS_device(), HLS_C));
153  }
154  else
155  {
156  HLSMgr->hlsMap[functionId]->operations = Operations;
157  }
158  return HLSMgr->hlsMap[functionId];
159 }
160 
161 std::string HLS_manager::get_constant_string(unsigned int node_id, unsigned long long precision)
162 {
163  std::string trimmed_value;
164  const auto node = TM->CGetTreeReindex(node_id);
165  const auto node_type = tree_helper::CGetType(node);
166  if(tree_helper::IsRealType(node_type))
167  {
168  THROW_ASSERT(tree_helper::Size(node_type) == precision, "real precision mismatch");
169  const auto rc = GetPointerS<const real_cst>(GET_CONST_NODE(node));
170  std::string C_value = rc->valr;
171  if(C_value == "Inf")
172  {
173  C_value = rc->valx;
174  }
175  if(C_value == "Nan" && rc->valx[0] == '-')
176  {
177  C_value = "-__Nan";
178  }
179  trimmed_value = convert_fp_to_string(C_value, precision);
180  }
181  else if(tree_helper::IsVectorType(node_type))
182  {
183  const auto vc = GetPointerS<const vector_cst>(GET_CONST_NODE(node));
184  auto n_elm = static_cast<unsigned int>(vc->list_of_valu.size());
185  auto elm_prec = precision / n_elm;
186  trimmed_value = "";
187  for(unsigned int i = 0; i < n_elm; ++i)
188  {
189  trimmed_value = get_constant_string(GET_INDEX_NODE(vc->list_of_valu[i]), elm_prec) + trimmed_value;
190  }
191  }
192  else if(tree_helper::IsComplexType(node_type))
193  {
194  const auto cc = GetPointerS<const complex_cst>(GET_CONST_NODE(node));
195  const auto rcc = GetPointer<const real_cst>(GET_CONST_NODE(cc->real));
196  std::string trimmed_value_r;
197  if(rcc)
198  {
199  std::string C_value_r = rcc->valr;
200  if(C_value_r == "Inf")
201  {
202  C_value_r = rcc->valx;
203  }
204  trimmed_value_r = convert_fp_to_string(C_value_r, precision / 2);
205  }
206  else
207  {
208  trimmed_value_r = convert_to_binary(tree_helper::GetConstValue(cc->real), precision / 2);
209  }
210  const auto icc = GetPointer<const real_cst>(GET_CONST_NODE(cc->imag));
211  std::string trimmed_value_i;
212  if(icc)
213  {
214  std::string C_value_i = icc->valr;
215  if(C_value_i == "Inf")
216  {
217  C_value_i = icc->valx;
218  }
219  trimmed_value_i = convert_fp_to_string(C_value_i, precision / 2);
220  }
221  else
222  {
223  trimmed_value_i = convert_to_binary(tree_helper::GetConstValue(cc->imag), precision / 2);
224  }
225  trimmed_value = trimmed_value_i + trimmed_value_r;
226  }
227  else
228  {
229  trimmed_value = convert_to_binary(tree_helper::GetConstValue(node), precision);
230  }
231  return trimmed_value;
232 }
233 
235 {
236  if(!back_flow)
237  {
238  back_flow = BackendFlow::CreateFlow(Param, "Synthesis", HLS_D);
239  }
240  return back_flow;
241 }
242 
243 void HLS_manager::xwrite(const std::string& filename)
244 {
245  try
246  {
247  xml_document document;
248  xml_element* nodeRoot = document.create_root_node("HLS");
249  Rmem->xwrite(nodeRoot);
250  for(const auto top_function : call_graph_manager->GetRootFunctions())
251  {
252  hlsRef HLS = hlsMap[top_function];
253  HLS->xwrite(nodeRoot, CGetFunctionBehavior(top_function)->CGetOpGraph(FunctionBehavior::FDFG));
254  }
255  document.write_to_file_formatted(filename);
256  }
257  catch(const char* msg)
258  {
259  std::cerr << msg << std::endl;
260  }
261  catch(const std::string& msg)
262  {
263  std::cerr << msg << std::endl;
264  }
265  catch(const std::exception& ex)
266  {
267  std::cout << "Exception caught: " << ex.what() << std::endl;
268  }
269  catch(...)
270  {
271  std::cerr << "unknown exception" << std::endl;
272  }
273 }
274 
275 std::vector<HLS_manager::io_binding_type> HLS_manager::get_required_values(unsigned int fun_id, const vertex& v) const
276 {
278  const auto& node = cfg->CGetOpNodeInfo(v)->node;
279  std::vector<io_binding_type> required;
280  if(node)
281  {
282  tree_helper::get_required_values(required, node);
283  }
284  return required;
285 }
286 
287 bool HLS_manager::is_register_compatible(unsigned int var) const
288 {
289  return tree_helper::is_ssa_name(TM, var) and
290  not tree_helper::is_virtual(TM, var) and // virtual ssa_name is not considered
292  TM, var) and // parameters have been already stored in a register by the calling function
293  not Rmem->has_base_address(var); // ssa_name allocated in memory
294 }
295 
297 {
298  auto fun_node = TM->get_tree_node_const(funID);
299  auto fd = GetPointer<function_decl>(fun_node);
300  THROW_ASSERT(fd, "unexpected condition");
301  return fd->reading_memory || fd->writing_memory;
302 }
303 
305 {
306  if(Param->getOption<bool>(OPT_gcc_serialize_memory_accesses))
307  {
308  return true;
309  }
310  return get_HLS_device() and get_HLS_device()->has_parameter("is_single_write_memory") and
311  get_HLS_device()->get_parameter<std::string>("is_single_write_memory") == "1";
312 }
313 
314 unsigned int HLS_manager::GetMemVersion() const
315 {
316  return memory_version;
317 }
318 
320 {
321  memory_version++;
322  return memory_version;
323 }
324 
325 void HLS_manager::check_bitwidth(unsigned long long prec)
326 {
327  if(prec > MAX_BITWIDTH_SIZE)
328  {
329  THROW_ERROR("The maximum bit-width size for connection is " + STR(MAX_BITWIDTH_SIZE) +
330  " Requested size: " + STR(prec));
331  }
332 }
333 
334 #define __TO_ENUM_HELPER(r, data, elem) {BOOST_PP_STRINGIZE(elem), data::elem},
335 #define TO_ENUM(enum_type, elem_list) \
336  static const std::unordered_map<std::string, enum enum_type> to_enum = { \
337  BOOST_PP_SEQ_FOR_EACH(__TO_ENUM_HELPER, enum_type, elem_list)}
338 
340 {
342  THROW_ASSERT(to_enum.find(attr) != to_enum.end(), "");
343  return to_enum.at(attr);
344 }
345 
347 {
349  THROW_ASSERT(to_enum.find(attr) != to_enum.end(), "");
350  return to_enum.at(attr);
351 }
352 
354 {
356  THROW_ASSERT(to_enum.find(attr) != to_enum.end(), "");
357  return to_enum.at(attr);
358 }
359 
361 {
362  pugi::xml_document doc;
363  pugi::xml_node n;
364  auto result = doc.load_file(filename.c_str());
365  if(result.status == pugi::xml_parse_status::status_file_not_found)
366  {
367  THROW_WARNING("Missing XML module architecture file.");
368  }
369  else if(result.status != pugi::xml_parse_status::status_ok)
370  {
371  THROW_ERROR("Unable to parse XML file: " + filename);
372  }
373  if((n = doc.child("module")))
374  {
375  for(auto& f : n)
376  {
377  THROW_ASSERT(!f.attribute("symbol").empty(), "Function symbol attribute missing from XML.");
378  auto& fa = _funcArchs[f.attribute("symbol").value()] =
380  for(auto& a : f.attributes())
381  {
382  fa->attrs.emplace(FunctionArchitecture::to_func_attr("func_" + std::string(a.name())), a.value());
383  }
384  for(auto& p : f.child("parameters"))
385  {
386  THROW_ASSERT(!p.attribute("port").empty(), "Parameter name attribute missing from XML.");
387  auto& parm_attrs = fa->parms[p.attribute("port").value()];
388  for(auto& a : p.attributes())
389  {
390  parm_attrs.emplace(FunctionArchitecture::to_parm_attr("parm_" + std::string(a.name())), a.value());
391  }
392  }
393  for(auto& i : f.child("bundles"))
394  {
395  THROW_ASSERT(!i.attribute("name").empty(), "Interface name attribute missing from XML.");
396  auto& iface_attr = fa->ifaces[i.attribute("name").value()];
397  for(auto& a : i.attributes())
398  {
399  iface_attr.emplace(FunctionArchitecture::to_iface_attr("iface_" + std::string(a.name())), a.value());
400  }
401  }
402  }
403  }
404 }
405 
407 
408 FunctionArchitectureRef ModuleArchitecture::GetArchitecture(const std::string& funcSymbol) const
409 {
410  auto it = _funcArchs.find(funcSymbol);
411  if(it != _funcArchs.end())
412  {
413  return it->second;
414  }
415  return nullptr;
416 }
417 
418 void ModuleArchitecture::AddArchitecture(const std::string& symbol, FunctionArchitectureRef arch)
419 {
420  _funcArchs[symbol] = arch;
421 }
422 
423 void ModuleArchitecture::RemoveArchitecture(const std::string& funcSymbol)
424 {
425  _funcArchs.erase(funcSymbol);
426 }
std::string convert_fp_to_string(std::string num, unsigned long long precision)
convert a real number stored in a string into a string of bits with a given precision ...
The information collected from aadl file.
static bool IsComplexType(const tree_nodeConstRef &type)
Return if treenode is a complex.
void xwrite(xml_element *node)
Writes the current memory allocation into an XML description.
Definition: memory.cpp:751
Data structure representing the entire HLS information.
bool IsSingleWriteMemory() const
Return if single write memory is exploited.
static std::string name_function(const tree_managerConstRef &tm, const unsigned int index)
Return the name of the function.
void AddArchitecture(const std::string &symbol, FunctionArchitectureRef arch)
const tree_nodeRef CGetTreeReindex(const unsigned int i) const
Return a tree_reindex wrapping the i-th tree_node.
std::string filename
~HLS_manager() override
Destructor.
#define FUNC_ARCH_PARM_ATTR_ENUM
Definition: hls_manager.hpp:67
ModuleArchitecture(const std::string &filename)
const tree_managerRef TM
class representing the application information at low level
std::string get_constant_string(unsigned int node, unsigned long long precision)
Return the specified constant in string format.
BackendFlowRef back_flow
reference to the data-structure implementing the backend flow
const FunctionBehaviorConstRef CGetFunctionBehavior(unsigned int index) const
Returns the data-structure associated with the given identifier.
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
G get_parameter(const std::string &key) const
Returns a parameter by key.
refcount< functions > functionsRef
refcount definition of the class
Definition: functions.hpp:159
FunctionArchitectureRef GetArchitecture(const std::string &funcSymbol) const
void xwrite(xml_element *rootnode, const OpGraphConstRef data)
Writes current HLS results to XML node.
Definition: hls.cpp:188
#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 enum func_attr to_func_attr(const std::string &attr)
static void get_required_values(std::vector< std::tuple< unsigned int, unsigned int >> &required, const tree_nodeRef &tn)
static hlsRef create_HLS(const HLS_managerRef HLSMgr, unsigned int functionId)
Creates the HLS flow starting from the given specification.
const ParameterConstRef Param
class containing all the parameters
A set of operation vertices.
Definition: op_graph.hpp:654
HLS_deviceRef HLS_D
information about the target device/technology for the synthesis
#define THROW_WARNING(str_expr)
helper function used to throw a warning in a standard way: though it uses PRINT_DBG_MEX, the debug level used is such that the message is always printed
Definition: exceptions.hpp:300
#define STR(s)
Macro which performs a lexical_cast to a string.
refcount< HLS_constraints > HLS_constraintsRef
refcount definition of the class
unsigned int memory_version
The version of memory representation on which this step was applied.
const BackendFlowRef get_backend_flow()
Returns the backend flow.
const tree_nodeRef get_tree_node_const(unsigned int i) const
Return the reference to the i-th tree_node Constant version of get_tree_node.
const OpNodeInfoConstRef CGetOpNodeInfo(const vertex node) const
Returns the info associated with a node.
Definition: op_graph.hpp:843
std::string convert_to_binary(G _value, unsigned long long precision)
Definition: utility.hpp:110
unsigned int UpdateMemVersion()
Update the version of the memory intermediate representation.
#define MAX_BITWIDTH_SIZE
Definition: hls_manager.cpp:68
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
Control flow graph.
static bool is_virtual(const tree_managerConstRef &TM, const unsigned int index)
return true in case the ssa_name is virtual
#define FUNC_ARCH_IFACE_ATTR_ENUM
Definition: hls_manager.hpp:70
memoryRef Rmem
information about memory allocation
void write_to_file_formatted(const std::filesystem::path &filename)
Write the document to a file.
xml_element * create_root_node(const std::string &_name)
Creates the root node.
bool is_reading_writing_function(unsigned funID) const
is_reading_writing_function
Datastructure to describe functions allocation in high-level synthesis.
XML DOM parser.
Data structure used to store all the HLS constraints.
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
bool is_register_compatible(unsigned int var) const
helper function that return true in case the variable is register compatible
static bool IsVectorType(const tree_nodeConstRef &type)
Return true if the treenode is a vector.
static BackendFlowRef CreateFlow(const ParameterConstRef Param, const std::string &flow_name, const generic_deviceRef _device)
Creates the flow specification based on the given parameters.
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
struct definition of the field attr on function_decl, field_decl, var_decl tree node.
Definition: tree_node.hpp:774
This file collects some utility functions and macros.
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
Data structure definition for HLS constraints.
int result[SIZE]
Definition: adpcm.c:800
static void check_bitwidth(unsigned long long prec)
check if the maximum bitwidth used for registers, busses, muxes, etc. is compatible with prec ...
used to avoid expansion of c library function or type
This file collects some utility functions.
hlsRef get_HLS(unsigned int funId) const
Returns the HLS data-structure associated with a specific function.
static bool is_ssa_name(const tree_managerConstRef &TM, const unsigned int index)
Return true in case index is a ssa_name.
static enum iface_attr to_iface_attr(const std::string &attr)
This file contains the definition of the configurable flow for generating and executing synthesis scr...
#define FUNC_ARCH_ATTR_ENUM
Definition: hls_manager.hpp:66
Data flow graph with feedback.
Class specification of the tree_reindex support class.
bool has_parameter(const std::string &key) const
Check if parameter exist.
bool has_base_address(unsigned int var) const
Check if there is a base address for the given variable.
Definition: memory.cpp:461
HLS_deviceRef get_HLS_device() const
Returns the data-structure associated with the HLS target.
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
const CallGraphManagerRef call_graph_manager
class representing the call graph of the application
std::map< unsigned int, hlsRef > hlsMap
map between the function id and the corresponding HLS data-structure
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.
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 RemoveArchitecture(const std::string &funcSymbol)
std::vector< io_binding_type > get_required_values(unsigned int fun_id, const vertex &v) const
Returns the values required by a vertex.
#define TO_ENUM(enum_type, elem_list)
Some macro used to interface with the XML library.
void xwrite(const std::string &filename)
Writes the current HLS project into an XML file.
Wrapper to call graph.
Data structure that contains all information about high level synthesis process.
Definition: hls.hpp:83
static integer_cst_t GetConstValue(const tree_nodeConstRef &tn, bool is_signed=true)
Get value from integer constant.
refcount< hls > hlsRef
refcount definition of the class
Definition: hls.hpp:268
HLS_manager(const ParameterConstRef Param, const HLS_deviceRef HLS_D)
Constructor.
Definition: hls_manager.cpp:90
Data structure definition for high-level synthesis flow.
static enum parm_attr to_parm_attr(const std::string &attr)
Datastructure to represent memory information in high-level synthesis.
functionsRef Rfuns
information about function allocation
Class specification of the manager of the tree structures extracted from the raw file.
unsigned int GetMemVersion() const
Return the version of the memory intermediate representation.
HLS specialization of generic_device.
A brief description of the C++ Header File.
static bool IsRealType(const tree_nodeConstRef &type)
Return true if the treenode is of real 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