HAL
register_stage_identification.cpp
Go to the documentation of this file.
2 
8 #include "hal_core/netlist/net.h"
10 #include "hal_core/utilities/log.h"
11 
12 #include <algorithm>
13 #include <chrono>
14 #include <list>
15 #include <queue>
16 #include <random>
17 
18 namespace hal
19 {
20  namespace dataflow
21  {
22  namespace pre_processing
23  {
25  {
26  measure_block_time("pre_processing_pass 'identify_register_stages'");
27 
28  struct stage_context
29  {
30  std::string name;
31  const std::unordered_map<u32, std::unordered_set<u32>>& connections;
32  std::vector<std::vector<u32>> stages;
33  };
34 
35  std::vector<stage_context> directional_stages = {{"forward", netlist_abstr.gate_to_successors, {}}, {"backward", netlist_abstr.gate_to_predecessors, {}}};
36 
37  for (auto& ctx : directional_stages)
38  {
39  log_info("dataflow", "directional register stages: {}", ctx.name);
40 
41  std::unordered_set<u32> unassigned_gates;
42  for (const auto& g : netlist_abstr.target_gates)
43  {
44  unassigned_gates.insert(g->get_id());
45  }
46 
47  {
48  measure_block_time(ctx.name + " analysis");
49  ProgressPrinter progress_bar;
50  float cnt = 0;
51  std::unordered_map<u32, u32> stage_index_of_gate;
52 
53  for (const auto& sequential_gate : netlist_abstr.target_gates)
54  {
55  cnt++;
56  progress_bar.print_progress(cnt / netlist_abstr.target_gates.size());
57 
58  auto current = sequential_gate->get_id();
59 
60  std::unordered_set<u32> next_stages;
61 
62  if (!ctx.connections.at(current).empty())
63  {
64  for (auto suc : ctx.connections.at(current))
65  {
66  if (auto it = stage_index_of_gate.find(suc); it != stage_index_of_gate.end())
67  {
68  next_stages.insert(it->second);
69  }
70  }
71 
72  // no stages
73  if (next_stages.empty())
74  {
75  ctx.stages.emplace_back(ctx.connections.at(current).begin(), ctx.connections.at(current).end());
76  auto new_stage_id = ctx.stages.size() - 1;
77  for (auto g : ctx.connections.at(current))
78  {
79  stage_index_of_gate[g] = new_stage_id;
80  }
81  }
82 
83  // multiple stages? merge!
84  if (next_stages.size() > 1)
85  {
86  auto it = next_stages.begin();
87  auto merge_stage_index = *it;
88  it++;
89  for (; it != next_stages.end(); it = next_stages.erase(it))
90  {
91  auto& stage_to_merge = ctx.stages[*it];
92  for (auto g : stage_to_merge)
93  {
94  stage_index_of_gate[g] = merge_stage_index;
95  }
96  ctx.stages[merge_stage_index].insert(ctx.stages[merge_stage_index].end(), stage_to_merge.begin(), stage_to_merge.end());
97  stage_to_merge.clear();
98  }
99  }
100 
101  // only one stage? directly or after merging
102  if (next_stages.size() == 1)
103  {
104  auto stage_index = *(next_stages.begin());
105  auto& connected_gates = ctx.connections.at(current);
106  ctx.stages[stage_index].insert(ctx.stages[stage_index].end(), connected_gates.begin(), connected_gates.end());
107  for (auto g : connected_gates)
108  {
109  stage_index_of_gate[g] = stage_index;
110  }
111  }
112 
113  for (auto g : ctx.connections.at(current))
114  {
115  if (auto it = unassigned_gates.find(g); it != unassigned_gates.end())
116  {
117  unassigned_gates.erase(it);
118  }
119  }
120  }
121  }
122  progress_bar.clear();
123  }
124 
125  {
126  ctx.stages.erase(std::remove_if(ctx.stages.begin(), ctx.stages.end(), [](auto& stage) { return stage.empty(); }), ctx.stages.end());
127 
128  measure_block_time("splitting stages");
129 
130  for (u32 i = 0; i < ctx.stages.size(); ++i)
131  {
132  std::sort(ctx.stages[i].begin(), ctx.stages[i].end());
133  ctx.stages[i].erase(std::unique(ctx.stages[i].begin(), ctx.stages[i].end()), ctx.stages[i].end());
134  }
135 
136  ProgressPrinter progress_bar;
137  float cnt = 0;
138 
139  u32 stages_to_split = ctx.stages.size();
140  for (u32 i = 0; i < stages_to_split; ++i)
141  {
142  ++cnt;
143  progress_bar.print_progress(cnt / stages_to_split);
144 
145  std::unordered_map<u32, std::vector<u32>> move_out_reasons;
146  for (auto g : ctx.stages[i])
147  {
148  for (auto next : ctx.connections.at(g))
149  {
150  if (next != g)
151  {
152  if (std::binary_search(ctx.stages[i].begin(), ctx.stages[i].end(), next) && ctx.connections.at(next).find(g) == ctx.connections.at(next).end())
153  {
154  move_out_reasons[next].push_back(g);
155  }
156  }
157  }
158  }
159 
160  for (auto it = move_out_reasons.begin(); it != move_out_reasons.end(); ++it)
161  {
162  std::sort(it->second.begin(), it->second.end());
163  it->second.erase(std::unique(it->second.begin(), it->second.end()), it->second.end());
164  }
165 
166  auto remaining = ctx.stages[i];
167  bool first_iteration = true;
168  while (!remaining.empty())
169  {
170  std::vector<u32> keep;
171  for (auto g : remaining)
172  {
173  if (move_out_reasons[g].empty())
174  {
175  keep.push_back(g);
176  }
177  }
178 
179  if (keep.empty() || keep.size() == remaining.size())
180  {
181  if (!first_iteration)
182  {
183  ctx.stages.push_back(remaining);
184  }
185  break;
186  }
187 
188  std::sort(keep.begin(), keep.end());
189  if (first_iteration)
190  {
191  ctx.stages[i] = keep;
192  }
193  else
194  {
195  ctx.stages.push_back(keep);
196  }
197 
198  {
199  std::vector<u32> diff;
200  std::set_difference(remaining.begin(), remaining.end(), keep.begin(), keep.end(), std::back_inserter(diff));
201  remaining = std::move(diff);
202  }
203 
204  for (auto r : remaining)
205  {
206  auto& reasons = move_out_reasons[r];
207  std::vector<u32> diff;
208  std::set_difference(reasons.begin(), reasons.end(), keep.begin(), keep.end(), std::back_inserter(diff));
209  reasons = std::move(diff);
210  }
211  first_iteration = false;
212  }
213  }
214 
215  progress_bar.clear();
216  }
217 
218  for (const auto& g : unassigned_gates)
219  {
220  ctx.stages.push_back({g});
221  }
222  }
223 
224  {
225  log_info("dataflow", "merging directional stages...");
226  measure_block_time("merging directional stages");
227 
228  ProgressPrinter progress_bar;
229 
230  for (u32 i = 0; i < 2; ++i)
231  {
232  std::sort(directional_stages[i].stages.begin(), directional_stages[i].stages.end(), [](auto& a, auto& b) { return a.size() < b.size(); });
233  }
234 
235  float cnt = 0;
236  for (u32 i = 0; i < 2; ++i)
237  {
238  for (const auto& stage : directional_stages[i].stages)
239  {
240  cnt++;
241  progress_bar.print_progress(cnt / (directional_stages[0].stages.size() + directional_stages[1].stages.size()));
242  for (auto it = directional_stages[1 - i].stages.begin(); it != directional_stages[1 - i].stages.end();)
243  {
244  auto& other_stage = *it;
245  if (stage.size() < other_stage.size())
246  {
247  break;
248  }
249 
250  if (std::includes(stage.begin(), stage.end(), other_stage.begin(), other_stage.end()))
251  {
252  it = directional_stages[1 - i].stages.erase(it);
253  }
254  else
255  {
256  ++it;
257  }
258  }
259  }
260  }
261 
262  progress_bar.clear();
263  }
264 
265  std::vector<std::vector<u32>> final_stages;
266 
267  {
268  log_info("dataflow", "sorting gates into final stages...");
269  measure_block_time("sorting gates into final stages");
270 
271  final_stages.reserve(directional_stages[0].stages.size() + directional_stages[1].stages.size());
272  for (u32 i = 0; i < 2; ++i)
273  {
274  final_stages.insert(final_stages.end(), directional_stages[i].stages.begin(), directional_stages[i].stages.end());
275  }
276 
277  netlist_abstr.gate_to_register_stages.clear();
278  for (u32 s = 0; s < final_stages.size(); ++s)
279  {
280  for (auto g : final_stages[s])
281  {
282  netlist_abstr.gate_to_register_stages[g].insert(s);
283  }
284  }
285  }
286 
287  {
288  log_info("dataflow", "spreading multi-stages...");
289  measure_block_time("spreading multi-stages");
290 
291  // step 1: precompute all stage indices that are in one multi-stage
292 
293  ProgressPrinter progress_bar;
294  float cnt = 0;
295  std::vector<std::unordered_set<u32>> spread_stages;
296  std::set<std::vector<u32>> seen;
297  for (auto& [g, stages] : netlist_abstr.gate_to_register_stages)
298  {
299  progress_bar.print_progress(++cnt / netlist_abstr.gate_to_register_stages.size());
300 
301  if (stages.size() > 1)
302  {
303  // collect current multi stage in vector for fast iteration + low memory
304  auto stages_vec = std::vector<u32>(stages.begin(), stages.end());
305 
306  // seen this multi stage before? skip!
307  if (seen.find(stages_vec) != seen.end())
308  {
309  continue;
310  }
311  seen.insert(stages_vec);
312 
313  // check if there is an existing multi stage to extend
314  auto it = std::find_if(spread_stages.begin(), spread_stages.end(), [&](auto& group) {
315  return std::any_of(stages_vec.begin(), stages_vec.end(), [&](auto id) { return group.find(id) != group.end(); });
316  });
317 
318  if (it != spread_stages.end())
319  {
320  // extend multi stage
321  it->insert(stages.begin(), stages.end());
322  }
323  else
324  {
325  // register new multi stage
326  spread_stages.emplace_back(stages.begin(), stages.end());
327  }
328  }
329  }
330 
331  // step 2: set the stages of all affected gates to the respective multi stage
332 
333  progress_bar.clear();
334  progress_bar.reset();
335 
336  cnt = 0;
337  for (const auto& combine : spread_stages)
338  {
339  progress_bar.print_progress(++cnt / netlist_abstr.gate_to_register_stages.size());
340 
341  for (auto stage_id : combine)
342  {
343  for (auto gate_id : final_stages[stage_id])
344  {
345  netlist_abstr.gate_to_register_stages[gate_id] = combine;
346  }
347  }
348  }
349  progress_bar.clear();
350  }
351 
352  log_info("dataflow", "found {} stages", final_stages.size());
353  }
354 
355  } // namespace pre_processing
356  } // namespace dataflow
357 } // namespace hal
void print_progress(float progress, const std::string &message="")
#define log_info(channel,...)
Definition: log.h:70
void identify_register_stages(NetlistAbstraction &netlist_abstr)
quint32 u32
std::string name
This file contains the struct that holds all information on the netlist abstraction used for dataflow...
The abstraction of the netlist that only contains gates of a specified type, e.g.,...
std::unordered_map< u32, std::unordered_set< u32 > > gate_to_predecessors
std::unordered_map< u32, std::unordered_set< u32 > > gate_to_register_stages
std::unordered_map< u32, std::unordered_set< u32 > > gate_to_successors
#define measure_block_time(X)
Definition: timing_utils.h:36