PandA-2024.02
create_tree_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 "create_tree_manager.hpp"
45 
46 #include "Parameter.hpp"
47 #include "application_manager.hpp"
48 #include "compiler_wrapper.hpp"
49 #include "config_HAVE_FROM_AADL_ASN_BUILT.hpp"
50 #include "config_HAVE_FROM_PRAGMA_BUILT.hpp"
51 #include "cost_latency_table.hpp"
52 #include "design_flow_graph.hpp"
53 #include "design_flow_manager.hpp"
54 #include "fileIO.hpp"
55 #include "hls_device.hpp"
56 #include "hls_manager.hpp"
57 #include "parse_tree.hpp"
58 #include "string_manipulation.hpp"
59 #include "technology_flow_step.hpp"
61 #include "technology_manager.hpp"
62 #include "technology_node.hpp"
63 #include "time_info.hpp"
64 #include "tree_manager.hpp"
65 #include "tree_reindex.hpp"
66 
67 #if HAVE_FROM_AADL_ASN_BUILT
68 #include "parser_flow_step.hpp"
69 #endif
70 
72  const DesignFlowManagerConstRef _design_flow_manager)
73  : ApplicationFrontendFlowStep(_AppM, CREATE_TREE_MANAGER, _design_flow_manager, _parameters),
74  compiler_wrapper(
75  new CompilerWrapper(parameters, parameters->getOption<CompilerWrapper_CompilerTarget>(OPT_default_compiler),
76  parameters->getOption<CompilerWrapper_OptimizationSet>(OPT_gcc_optimization_set)))
77 {
78  debug_level = parameters->get_class_debug_level(GET_CLASS(*this), DEBUG_LEVEL_NONE);
79 }
80 
82 
84  const DesignFlowStep::RelationshipType relationship_type)
85 {
86  switch(relationship_type)
87  {
89  {
90  break;
91  }
93  {
94 #if HAVE_FROM_AADL_ASN_BUILT
95  if(parameters->getOption<Parameters_FileFormat>(OPT_input_format) == Parameters_FileFormat::FF_AADL)
96  {
97  for(const auto& input_file : AppM->input_files)
98  {
99  const auto file_format = parameters->GetFileFormat(input_file);
100  if(file_format == Parameters_FileFormat::FF_AADL)
101  {
102  const auto signature = ParserFlowStep::ComputeSignature(ParserFlowStep_Type::AADL, input_file);
103  vertex parser_step = design_flow_manager.lock()->GetDesignFlowStep(signature);
104  const DesignFlowGraphConstRef design_flow_graph = design_flow_manager.lock()->CGetDesignFlowGraph();
105  const DesignFlowStepRef design_flow_step =
106  parser_step != NULL_VERTEX ?
107  design_flow_graph->CGetDesignFlowStepInfo(parser_step)->design_flow_step :
108  design_flow_manager.lock()->CreateFlowStep(signature);
109  relationship.insert(design_flow_step);
110  }
111  else if(file_format == Parameters_FileFormat::FF_ASN)
112  {
113  const auto signature = ParserFlowStep::ComputeSignature(ParserFlowStep_Type::ASN, input_file);
114  vertex parser_step = design_flow_manager.lock()->GetDesignFlowStep(signature);
115  const DesignFlowGraphConstRef design_flow_graph = design_flow_manager.lock()->CGetDesignFlowGraph();
116  const DesignFlowStepRef design_flow_step =
117  parser_step != NULL_VERTEX ?
118  design_flow_graph->CGetDesignFlowStepInfo(parser_step)->design_flow_step :
119  design_flow_manager.lock()->CreateFlowStep(signature);
120  relationship.insert(design_flow_step);
121  }
122  }
123  }
124 #endif
125  const DesignFlowGraphConstRef design_flow_graph = design_flow_manager.lock()->CGetDesignFlowGraph();
126  const auto* technology_flow_step_factory = GetPointer<const TechnologyFlowStepFactory>(
127  design_flow_manager.lock()->CGetDesignFlowStepFactory("Technology"));
128  const std::string technology_flow_signature =
130  const vertex technology_flow_step = design_flow_manager.lock()->GetDesignFlowStep(technology_flow_signature);
131  const DesignFlowStepRef technology_design_flow_step =
132  technology_flow_step ?
133  design_flow_graph->CGetDesignFlowStepInfo(technology_flow_step)->design_flow_step :
134  technology_flow_step_factory->CreateTechnologyFlowStep(TechnologyFlowStep_Type::LOAD_TECHNOLOGY);
135  relationship.insert(technology_design_flow_step);
136  break;
137  }
139  {
140  break;
141  }
142  default:
143  THROW_UNREACHABLE("");
144  }
145  ApplicationFrontendFlowStep::ComputeRelationships(relationship, relationship_type);
146 }
147 
150 {
152  switch(relationship_type)
153  {
155  {
156  break;
157  }
159  {
160 #if HAVE_FROM_PRAGMA_BUILT
161  relationships.insert(std::make_pair(PRAGMA_SUBSTITUTION, WHOLE_APPLICATION));
162 #endif
163  break;
164  }
166  {
167  break;
168  }
169  default:
170  {
171  THROW_UNREACHABLE("");
172  }
173  }
174  return relationships;
175 }
176 
178 {
179  return true;
180 }
181 
183 {
184  if(GetPointer<HLS_manager>(AppM) &&
185  (!parameters->IsParameter("disable-THR") || parameters->GetParameter<unsigned int>("disable-THR") == 0))
186  {
187  std::map<std::pair<std::string, std::string>, std::string> default_InstructionLatencyTable;
188  auto latencies = SplitString(STR_cost_latency_table_default, ",");
189  for(const auto& el : latencies)
190  {
191  auto key_value = SplitString(el, "=");
192  THROW_ASSERT(key_value.size() == 2, "unexpected condition");
193  auto op_bit = SplitString(key_value.at(0), "|");
194  THROW_ASSERT(op_bit.size() == 2, "unexpected condition");
195  default_InstructionLatencyTable[std::make_pair(op_bit.at(0), op_bit.at(1))] = key_value.at(1);
196  }
197 
198  const HLS_deviceRef HLS_D = GetPointer<HLS_manager>(AppM)->get_HLS_device();
199  const technology_managerRef TechManager = HLS_D->get_technology_manager();
200  double clock_period =
201  parameters->isOption(OPT_clock_period) ? parameters->getOption<double>(OPT_clock_period) : 10;
203  CostTable = "store_expr|32=" + STR(clock_period);
204  CostTable += ",load_expr|32=" + STR(clock_period);
205  CostTable += ",nop_expr|32=" + STR(clock_period);
206  for(const std::string op_name : {"mult_expr", "plus_expr", "trunc_div_expr", "trunc_mod_expr", "lshift_expr",
207  "rshift_expr", "bit_and_expr", "bit_ior_expr", "bit_xor_expr", "cond_expr"})
208  {
209  for(auto fu_prec : {1, 8, 16, 32, 64})
210  {
211  auto component_name_op =
212  "ui_" + op_name + std::string("_FU_") + STR(fu_prec) + "_" + STR(fu_prec) + "_" + STR(fu_prec) +
213  ((op_name == "mult_expr" || op_name == "trunc_div_expr" || op_name == "trunc_mod_expr") ? "_0" : "") +
214  (op_name == "cond_expr" ? ("_" + STR(fu_prec)) : "");
215  technology_nodeRef op_f_unit = TechManager->get_fu(component_name_op, LIBRARY_STD_FU);
216  if(op_f_unit)
217  {
218  auto* op_fu = GetPointer<functional_unit>(op_f_unit);
219  technology_nodeRef op_node = op_fu->get_operation(op_name);
220  THROW_ASSERT(op_node, "missing " + op_name + " from " + component_name_op);
221  auto* op = GetPointer<operation>(op_node);
222  double op_delay = op->time_m->get_execution_time();
223  CostTable += "," + op_name + "|" + STR(fu_prec) + "=" + STR(op_delay);
224  }
225  else
226  {
227  THROW_ASSERT(default_InstructionLatencyTable.find(std::make_pair(op_name, STR(fu_prec))) !=
228  default_InstructionLatencyTable.end(),
229  "");
230  CostTable += "," + op_name + "|" + STR(fu_prec) + "=" +
231  default_InstructionLatencyTable.at(std::make_pair(op_name, STR(fu_prec)));
232  }
233  }
234  }
235  for(const std::string op_name : {"mult_expr", "plus_expr", "rdiv_expr"})
236  {
237  for(auto fu_prec : {32, 64})
238  {
239  auto component_name_op = "fp_" + op_name + std::string("_FU_") + STR(fu_prec) + "_" + STR(fu_prec) + "_" +
240  STR(fu_prec) + ((op_name == "mult_expr") ? "_200" : "_100");
241  technology_nodeRef op_f_unit = TechManager->get_fu(component_name_op, LIBRARY_STD_FU);
242  if(op_f_unit)
243  {
244  auto* op_fu = GetPointer<functional_unit>(op_f_unit);
245  technology_nodeRef op_node = op_fu->get_operation(op_name);
246  THROW_ASSERT(op_node, "missing " + op_name + " from " + component_name_op);
247  auto* op = GetPointer<operation>(op_node);
248  auto op_cycles = op->time_m->get_cycles();
249  double op_delay = op_cycles ? clock_period * op_cycles : op->time_m->get_execution_time();
250  CostTable += ",F" + op_name + "|" + STR(fu_prec) + "=" + STR(op_delay);
251  }
252  else
253  {
254  THROW_ASSERT(default_InstructionLatencyTable.find(std::make_pair("F" + op_name, STR(fu_prec))) !=
255  default_InstructionLatencyTable.end(),
256  "");
257  CostTable += "," + op_name + "|" + STR(fu_prec) + "=" +
258  default_InstructionLatencyTable.at(std::make_pair("F" + op_name, STR(fu_prec)));
259  }
260  }
261  }
262  }
263 }
264 
266 {
267  const auto TM = AppM->get_tree_manager();
268 
269  if(!parameters->isOption(OPT_input_file))
270  {
271  THROW_ERROR("At least one source file has to be passed to the tool");
272  }
273 
275  if(parameters->isOption(OPT_archive_files))
276  {
277  const auto archive_files = parameters->getOption<CustomSet<std::string>>(OPT_archive_files);
278  const auto output_temporary_directory = parameters->getOption<std::string>(OPT_output_temporary_directory);
279  const auto temp_path = output_temporary_directory + "archives";
280  std::filesystem::create_directories(temp_path);
281  std::string command = "cd " + temp_path + "\n";
282  for(const auto& archive_file : archive_files)
283  {
284  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Reading " + archive_file);
285  if(!std::filesystem::exists(std::filesystem::path(archive_file)))
286  {
287  THROW_ERROR("File " + archive_file + " does not exist");
288  }
289  const auto local_archive_file = GetPath(archive_file);
290 
291  command += " ar x " + local_archive_file + " &\n";
292  }
293  command += " wait";
294  if(IsError(PandaSystem(parameters, command)))
295  {
296  THROW_ERROR("ar returns an error during archive extraction ");
297  }
298  for(const auto& archive : std::filesystem::directory_iterator{temp_path})
299  {
300  const auto fileExtension = archive.path().extension().string();
301  if(fileExtension != ".o" && fileExtension != ".O")
302  {
303  continue;
304  }
305  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "--Loading " + archive.path().string());
306  const auto TM_new = ParseTreeFile(parameters, archive.path().string());
307  TM->merge_tree_managers(TM_new);
308  }
309  if(!parameters->getOption<bool>(OPT_no_clean))
310  {
311  std::filesystem::remove_all(temp_path);
312  }
313  }
314 
315  if(parameters->getOption<Parameters_FileFormat>(OPT_input_format) == Parameters_FileFormat::FF_RAW)
316  {
318  {
320  {
325  "*********************************************************************************");
327  "* Building internal representation from raw files *");
329  "*********************************************************************************");
330  }
331  else
332  {
335  " =============== Building internal representation from raw files ===============");
336  }
337  }
338  const auto raw_files = parameters->getOption<CustomSet<std::string>>(OPT_input_file);
339  for(const auto& raw_file : raw_files)
340  {
341  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "Parsing " + raw_file);
342  if(!std::filesystem::exists(std::filesystem::path(raw_file)))
343  {
344  THROW_ERROR("File " + raw_file + " does not exist");
345  }
346  tree_managerRef TM_tmp = ParseTreeFile(parameters, raw_file);
347  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Merging " + raw_file);
348  TM->merge_tree_managers(TM_tmp);
349  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Merged " + raw_file);
350  }
351  }
352  else
353  {
354 #if !RELEASE
355  // if a XML configuration file has been specified for the GCC/CLANG parameters
356  if(parameters->isOption(OPT_gcc_read_xml))
357  {
358  compiler_wrapper->ReadXml(parameters->getOption<std::string>(OPT_gcc_read_xml));
359  }
360 #endif
361  createCostTable();
362  compiler_wrapper->FillTreeManager(TM, AppM->input_files, getCostTable());
363 
364 #if !RELEASE
365  if(parameters->isOption(OPT_gcc_write_xml))
366  {
367  compiler_wrapper->WriteXml(parameters->getOption<std::string>(OPT_gcc_write_xml));
368  }
369 #endif
370 
372  {
373  std::string raw_file_name =
374  parameters->getOption<std::string>(OPT_output_temporary_directory) + "after_raw_merge.raw";
375  std::ofstream raw_file(raw_file_name.c_str());
376  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "Tree-Manager dumped for debug purpose");
377  raw_file << TM;
378  raw_file.close();
379  }
380  }
381 
382  const auto HLSMgr = GetPointer<HLS_manager>(AppM);
383  THROW_ASSERT(HLSMgr, "");
384  const auto arch_filename =
385  parameters->isOption(OPT_architecture_xml) ?
386  parameters->getOption<std::string>(OPT_architecture_xml) :
387  (parameters->getOption<std::string>(OPT_output_temporary_directory) + "/architecture.xml");
388  HLSMgr->module_arch = refcount<ModuleArchitecture>(new ModuleArchitecture(arch_filename));
389 
390  for(auto& [symbol, arch] : *HLSMgr->module_arch)
391  {
392  const auto fnode = TM->GetFunction(symbol);
393  if(!fnode)
394  {
395  THROW_WARNING("Function specified in architecture XML is missing in the IR: " + symbol);
396  continue;
397  }
398  const auto fd = GetPointer<function_decl>(GET_NODE(fnode));
399  for(auto& [attr, val] : arch->attrs)
400  {
401  if(attr == FunctionArchitecture::func_pipeline_style)
402  {
403  if(val == "off")
404  {
405  fd->set_pipelining(false);
406  }
407  else
408  {
409  fd->set_pipelining(true);
410  if(val == "frp")
411  {
412  fd->set_simple_pipeline(true);
413  }
414  }
415  }
416  else if(attr == FunctionArchitecture::func_pipeline_ii)
417  {
418  const auto pipeline_ii = std::stoi(val);
419  fd->set_initiation_time(pipeline_ii);
420  }
421  }
422  }
423 
425 }
#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.
static const std::string ComputeSignature(const ParserFlowStep_Type parser_step_type, const std::string &file_name)
Compute the signature of a parser flow step.
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;.
This class contains the base representation for a generic parser step.
#define DEBUG_LEVEL_PEDANTIC
very verbose debugging print is performed.
technology_nodeRef get_fu(const std::string &fu_name, const std::string &Library) const
Return the reference to a component given its name.
Class that creates the tree_manager starting from the source code files.
#define GET_CLASS(obj)
Macro returning the actual type of an object.
Definition of the class representing a generic C application.
const int output_level
The output level.
const std::vector< std::string > SplitString(const std::string &input, const std::string &separators)
Function which splits a string into tokens.
RelationshipType
The relationship type.
Source must be executed to satisfy target.
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
Collect information about resource performance.
DesignFlowStep_Status Exec() override
Creates the tree_manager data structure by invoking the GCC/CLANG wrapper.
Specification of the tree (GCC raw) parsing interface function.
#define LIBRARY_STD_FU
standard library where all standard HLS resources are defined
Class specification of the manager of the technology library data structures.
std::string CostTable
CostTable: string storing the operations&#39; latency in an encoded map.
#define OUTPUT_LEVEL_MINIMUM
minimum debugging print is performed.
CompilerWrapper_OptimizationSet
Possible optimization sets.
#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.
Auxiliary methods for manipulating string.
bool IsError(const int error_value)
Utility include.
Definition: exceptions.cpp:58
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
void ComputeRelationships(DesignFlowStepSet &relationship, const DesignFlowStep::RelationshipType relationship_type) override
Compute the relationships of a step with other steps.
~create_tree_manager() override
Destructor.
Class specification of the data structures used to manage technology information. ...
create_tree_manager(const ParameterConstRef _parameters, const application_managerRef AppM, const DesignFlowManagerConstRef design_flow_manager)
Constructor.
default table used by THR LLVM optimization step.
void createCostTable()
createCostTable: Fill the CostTable starting from the technology files
Classes to describe design flow graph.
static const std::string ComputeSignature(const TechnologyFlowStep_Type technology_flow_step_type)
Compute the signature of a technology flow step.
Factory for technology flow step.
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
utility function used to read files.
CompilerWrapper_CompilerTarget
target of the compiler
const Wrefcount< const DesignFlowManager > design_flow_manager
The design flow manager.
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
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.
struct definition of the field attr on function_decl, field_decl, var_decl tree node.
Definition: tree_node.hpp:774
#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
Wrapper of design_flow.
list command
Definition: test_panda.py:921
#define STR_cost_latency_table_default
default string for latencies
int PandaSystem(const ParameterConstRef Param, const std::string &system_command, bool host_exec, const std::string &output, const unsigned int type, const bool background, const size_t timeout)
System call forcing execution with bash.
Definition: fileIO.cpp:78
refcount< T > lock() const
Definition: refcount.hpp:212
void ComputeRelationships(DesignFlowStepSet &relationship, const DesignFlowStep::RelationshipType relationship_type) override
Compute the relationships of a step with other steps.
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
std::string GetPath(std::filesystem::path path)
Definition: fileIO.hpp:140
const application_managerRef AppM
The application manager.
int el
Definition: adpcm.c:105
Class specification of the tree_reindex support class.
technology_managerRef get_technology_manager() const
Returns the technology manager.
const CompilerWrapperRef compiler_wrapper
The gcc wrapper.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
const std::string getCostTable() const
return the latency table used by THR to balance the computation
Parameters_FileFormat
File formats.
Definition: Parameter.hpp:261
this class is used to manage the command-line or XML options.
Main class for wrapping the frontend compiler.
int debug_level
The debug level.
#define OUTPUT_LEVEL_VERBOSE
verbose debugging print is performed.
#define NULL_VERTEX
null vertex definition
Definition: graph.hpp:1305
tree_managerRef ParseTreeFile(const ParameterConstRef &Param, const std::string &f)
Function that parse the dump of the patched GCC.
Definition: parse_tree.cpp:59
Class specification of the manager of the tree structures extracted from the raw file.
Base class for technology flow steps.
HLS specialization of generic_device.
#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
Implementation of the wrapper to Gcc for C sources.

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