PandA-2024.02
HWPathComputation.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  */
36 #include "HWPathComputation.hpp"
37 
38 #include "Discrepancy.hpp"
39 #include "UnfoldedCallInfo.hpp"
40 #include "UnfoldedFunctionInfo.hpp"
41 #include "behavioral_helper.hpp"
42 #include "call_graph_manager.hpp"
43 #include "dbgPrintHelper.hpp"
44 #include "fu_binding.hpp"
45 #include "function_behavior.hpp"
46 #include "functions.hpp"
47 #include "hls.hpp"
48 #include "hls_manager.hpp"
49 #include "hls_step.hpp"
50 #include "op_graph.hpp"
51 #include "structural_objects.hpp"
52 #include "utility.hpp"
53 
54 #include <utility>
55 
56 class HWCallPathCalculator : public boost::default_dfs_visitor
57 {
58  protected:
61 
63  std::stack<std::string> scope;
64 
66  // scope of that shared function
67  std::map<std::string, std::string> shared_fun_scope;
68 
70  // it is computed by start_vertex
71  std::string top_fun_scope;
72 
73  public:
74  HWCallPathCalculator(const HLS_managerRef _HLSMgr);
75 
76  void start_vertex(const UnfoldedVertexDescriptor& v, const UnfoldedCallGraph& ufcg);
79  void examine_edge(const EdgeDescriptor& e, const UnfoldedCallGraph& cg);
80 };
81 
83 {
84  THROW_ASSERT(HLSMgr->RDiscr, "Discr data structure is not correctly initialized");
85 }
86 
88 {
89  scope = std::stack<std::string>();
90  shared_fun_scope.clear();
91  const auto top_fu_name =
92  Cget_node_info<UnfoldedFunctionInfo>(v, ufcg)->behavior->CGetBehavioralHelper()->get_function_name();
93 
94  top_fun_scope = "clocked_bambu_testbench" HIERARCHY_SEPARATOR "bambu_testbench" HIERARCHY_SEPARATOR
96  top_fu_name + "_i0" HIERARCHY_SEPARATOR;
97 
98  HLSMgr->RDiscr->unfolded_v_to_scope[v] = top_fun_scope;
99  const auto f_id = Cget_node_info<UnfoldedFunctionInfo>(v, ufcg)->f_id;
100  HLSMgr->RDiscr->f_id_to_scope[f_id].insert(top_fun_scope);
101 }
102 
104 {
105  // get the function id
106  const auto BH = Cget_node_info<UnfoldedFunctionInfo>(v, ufcg)->behavior->CGetBehavioralHelper();
107  const auto f_id = Cget_node_info<UnfoldedFunctionInfo>(v, ufcg)->f_id;
108  if(!BH->has_implementation() || !BH->function_has_to_be_printed(f_id))
109  {
110  scope.push("");
111  return;
112  }
113  THROW_ASSERT(HLSMgr->RDiscr->unfolded_v_to_scope.count(v), "can't find scope for function " + STR(f_id));
114  scope.push(HLSMgr->RDiscr->unfolded_v_to_scope.at(v));
115  THROW_ASSERT(!scope.top().empty(), "Empty HW scope for function " + STR(f_id));
116  /*
117  * if there are shared functions allocated in this vertex, store their scope
118  * in the map, so it can be pushed on the scope stack later, when the
119  * exploration of the call graph reaches the vertex corresponding to those
120  * functions
121  */
122  if(HLSMgr->Rfuns->has_shared_functions(f_id))
123  {
124  for(const auto& shared_fu_name : HLSMgr->Rfuns->get_shared_functions(f_id))
125  {
126  const auto fu_scope = scope.top() + "Datapath_i" HIERARCHY_SEPARATOR + shared_fu_name +
127  "_instance" HIERARCHY_SEPARATOR + shared_fu_name + "_i" HIERARCHY_SEPARATOR;
128  shared_fun_scope[shared_fu_name] = fu_scope;
129  }
130  }
131 }
132 
134 {
135  scope.pop();
136 }
137 
139 {
140  const auto tgt = boost::target(e, ufcg);
141  const auto called_f_id = Cget_node_info<UnfoldedFunctionInfo>(tgt, ufcg)->f_id;
142  const auto BH = Cget_node_info<UnfoldedFunctionInfo>(tgt, ufcg)->behavior->CGetBehavioralHelper();
143  if(!BH->has_implementation() || !BH->function_has_to_be_printed(called_f_id))
144  {
145  return;
146  }
147 
148  const auto called_fu_name = [&]() {
149  const auto fu_name = functions::GetFUName(BH->get_function_name(), HLSMgr);
150  return starts_with(fu_name, WRAPPED_PROXY_PREFIX) ? fu_name.substr(sizeof(WRAPPED_PROXY_PREFIX) - 1) : fu_name;
151  }();
152  std::string called_scope;
153  if(HLSMgr->Rfuns->is_a_proxied_function(called_fu_name))
154  {
155  THROW_ASSERT(shared_fun_scope.count(called_fu_name), called_fu_name + " was not allocated in a dominator");
156  called_scope = shared_fun_scope.at(called_fu_name);
157  }
158  else
159  {
160  if(Cget_raw_edge_info<UnfoldedCallInfo>(e, ufcg)->is_direct)
161  {
162  const auto call_id = Cget_raw_edge_info<UnfoldedCallInfo>(e, ufcg)->call_id;
163  THROW_ASSERT(call_id != 0U, "No artificial calls allowed in UnfoldedCallGraph");
164  const auto src = boost::source(e, ufcg);
165  const auto& caller_f_id = Cget_node_info<UnfoldedFunctionInfo>(src, ufcg)->f_id;
166  const auto& caller_behavior = Cget_node_info<UnfoldedFunctionInfo>(src, ufcg)->behavior;
167  const auto op_graph = caller_behavior->CGetOpGraph(FunctionBehavior::CFG);
168  const auto call_op_v = op_graph->CGetOpGraphInfo()->tree_node_to_operation.at(call_id);
169  const auto& fu_bind = HLSMgr->get_HLS(caller_f_id)->Rfu;
170  const auto fu_type_id = fu_bind->get_assign(call_op_v);
171  const auto fu_instance_id = fu_bind->get_index(call_op_v);
172  std::string extra_path;
173  if(HLSMgr->hasToBeInterfaced(called_f_id))
174  {
175  extra_path += called_fu_name + "_int_i0" HIERARCHY_SEPARATOR;
176  }
177 
178  if(fu_bind->get_operations(fu_type_id, fu_instance_id).size() == 1U)
179  {
180  called_scope = scope.top() + "Datapath_i" HIERARCHY_SEPARATOR "fu_" + GET_NAME(op_graph, call_op_v) +
181  HIERARCHY_SEPARATOR + extra_path;
182  }
183  else
184  {
185  called_scope = scope.top() + "Datapath_i" HIERARCHY_SEPARATOR + fu_bind->get_fu_name(call_op_v) + "_i" +
186  STR(fu_bind->get_index(call_op_v)) + HIERARCHY_SEPARATOR + extra_path;
187  }
188  }
189  else
190  {
191  called_scope = top_fun_scope + "Datapath_i" HIERARCHY_SEPARATOR + called_fu_name + "_i0" HIERARCHY_SEPARATOR +
192  called_fu_name + "_int_i0" HIERARCHY_SEPARATOR;
193  }
194  }
195  HLSMgr->RDiscr->f_id_to_scope[called_f_id].insert(called_scope);
196  HLSMgr->RDiscr->unfolded_v_to_scope[tgt] = called_scope;
197 }
198 
200  const DesignFlowManagerConstRef _design_flow_manager)
201  : HLS_step(_Param, _HLSMgr, _design_flow_manager, HLSFlowStep_Type::HW_PATH_COMPUTATION)
202 {
203 }
204 
206 
209 {
211 
212  switch(relationship_type)
213  {
215  {
220  break;
221  }
224  {
225  break;
226  }
227  default:
228  {
229  THROW_UNREACHABLE("");
230  }
231  }
232  return ret;
233 }
234 
236 {
237  return true;
238 }
239 
241 {
242  // Calculate the HW paths and store them in Discrepancy
243  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "-->Unfolding call graph");
244  HWCallPathCalculator sig_sel_v(HLSMgr);
245  std::vector<boost::default_color_type> sig_sel_color(boost::num_vertices(HLSMgr->RDiscr->DiscrepancyCallGraph),
246  boost::white_color);
247  boost::depth_first_visit(
248  HLSMgr->RDiscr->DiscrepancyCallGraph, HLSMgr->RDiscr->unfolded_root_v, sig_sel_v,
249  boost::make_iterator_property_map(sig_sel_color.begin(),
250  boost::get(boost::vertex_index_t(), HLSMgr->RDiscr->DiscrepancyCallGraph),
251  boost::white_color));
252  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "<--Unfolded call graph");
254 }
const HLS_managerRef HLSMgr
information about all the HLS synthesis
Definition: hls_step.hpp:205
std::stack< std::string > scope
a stack of scopes used during the traversal of the UnfoldedCallGraph
Data structure representing the entire HLS information.
HWCallPathCalculator(const HLS_managerRef _HLSMgr)
File containing functions and utilities to support the printing of debug messagges.
string target
Definition: lenet_tvm.py:16
const int output_level
The output level.
RelationshipType
The relationship type.
Source must be executed to satisfy target.
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
#define GET_NAME(data, vertex_index)
Helper macro returning the name associated with a node.
std::string top_fun_scope
The scope of the top function. It depends on different parameters and.
const HLS_managerRef HLSMgr
a refcount to the HLS_manager
#define STR(s)
Macro which performs a lexical_cast to a string.
~HWPathComputation() override
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
bool starts_with(const std::string &str, const std::string &pattern)
Control flow graph.
HWPathComputation(const ParameterConstRef Param, const HLS_managerRef HLSMgr, const DesignFlowManagerConstRef design_flow_manager)
HLSFlowStep_Type
Definition: hls_step.hpp:95
const CustomUnorderedSet< std::tuple< HLSFlowStep_Type, HLSFlowStepSpecializationConstRef, HLSFlowStep_Relationship > > ComputeHLSRelationships(const DesignFlowStep::RelationshipType relationship_type) const override
Return the set of analyses in relationship with this design step.
Datastructure to describe functions allocation in high-level synthesis.
void finish_vertex(const UnfoldedVertexDescriptor &v, const UnfoldedCallGraph &)
static std::string GetFUName(const std::string &fname, const HLS_managerRef HLSMgr)
Return FU used to implement given function.
Definition: functions.cpp:118
std::map< std::string, std::string > shared_fun_scope
The key is the name of a shared function, the mapped value is the HW.
DesignFlowStep_Status
The status of a step.
This file collects some utility functions and macros.
boost::graph_traits< UnfoldedCallGraph >::vertex_descriptor UnfoldedVertexDescriptor
#define WRAPPED_PROXY_PREFIX
#define HIERARCHY_SEPARATOR
This class describes all classes used to represent a structural object.
void examine_edge(const EdgeDescriptor &e, const UnfoldedCallGraph &cg)
Data structure used to store the functional-unit binding of the vertexes.
Data structures used in operations graph.
void discover_vertex(const UnfoldedVertexDescriptor &v, const UnfoldedCallGraph &ufcg)
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
Wrapper to call graph.
#define OUTPUT_LEVEL_VERBOSE
verbose debugging print is performed.
refcount< const HLSFlowStepSpecialization > HLSFlowStepSpecializationConstRef
const refcount definition of the class
Definition: hls_step.hpp:93
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
void start_vertex(const UnfoldedVertexDescriptor &v, const UnfoldedCallGraph &ufcg)
Data structure definition for high-level synthesis flow.
DesignFlowStep_Status Exec() override
Execute the step.
A brief description of the C++ Header File.
boost::graph_traits< graph >::edge_descriptor EdgeDescriptor
edge definition.
Definition: graph.hpp:1316
#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:54 for PandA-2024.02 by doxygen 1.8.13