HAL
grouping.cpp
Go to the documentation of this file.
2 
7 
8 namespace hal
9 {
10  namespace dataflow
11  {
12  Grouping::Grouping(const NetlistAbstraction& na) : netlist_abstr(na)
13  {
14  }
15 
16  Grouping::Grouping(const NetlistAbstraction& na, const std::vector<std::vector<Gate*>>& groups) : Grouping(na)
17  {
18  /* initialize state */
19  i32 new_id_counter = -1;
20  bool group_is_known;
21 
22  for (const auto* gate : na.target_gates)
23  {
24  group_is_known = false;
25  for (const auto& gates : groups)
26  {
27  for (const auto* g : gates)
28  {
29  if (gate == g)
30  {
31  group_is_known = true;
32  break;
33  }
34  }
35  if (group_is_known)
36  {
37  break;
38  }
39  }
40  if (!group_is_known)
41  {
42  u32 new_group_id = (u32)(++new_id_counter);
43 
44  this->group_control_fingerprint_map[new_group_id] = na.gate_to_fingerprint.at(gate->get_id());
45 
46  this->gates_of_group[new_group_id].insert(gate->get_id());
47  this->parent_group_of_gate[gate->get_id()] = new_group_id;
48 
49  this->operations_on_group_allowed[new_group_id] = true;
50  }
51  }
52 
53  /* merge groups known before execution */
54  for (const auto& gates : groups)
55  {
56  if (gates.empty())
57  {
58  continue;
59  }
60 
61  u32 new_group_id = (u32)(++new_id_counter);
62 
63  this->operations_on_group_allowed[new_group_id] = false;
64  this->group_control_fingerprint_map[new_group_id] = na.gate_to_fingerprint.at(gates.front()->get_id());
65 
66  for (const auto& g : gates)
67  {
68  auto gid = g->get_id();
69  this->gates_of_group[new_group_id].insert(gid);
70  this->parent_group_of_gate[gid] = new_group_id;
71  }
72  }
73  }
74 
75  Grouping::Grouping(const Grouping& other) : Grouping(other.netlist_abstr)
76  {
80  }
81 
82  const std::set<std::set<u32>>& Grouping::get_comparison_data() const
83  {
84  if (cache.comparison_cache.empty())
85  {
86  for (const auto& it : gates_of_group)
87  {
88  cache.comparison_cache.emplace(it.second.begin(), it.second.end());
89  }
90  }
91  return cache.comparison_cache;
92  }
93 
94  bool Grouping::operator==(const Grouping& other) const
95  {
96  if (gates_of_group.size() != other.gates_of_group.size())
97  {
98  return false;
99  }
100 
101  return get_comparison_data() == other.get_comparison_data();
102  }
103 
104  bool Grouping::operator!=(const Grouping& other) const
105  {
106  return !(*this == other);
107  }
108 
109  std::map<PinType, std::unordered_set<u32>> Grouping::get_control_signals_of_group(u32 group_id) const
110  {
111  std::map<PinType, std::unordered_set<u32>> res;
112 
113  for (auto gate : gates_of_group.at(group_id))
114  {
115  if (auto it = this->netlist_abstr.gate_to_control_signals.find(gate); it != this->netlist_abstr.gate_to_control_signals.end())
116  {
117  res.insert(it->second.begin(), it->second.end());
118  }
119  }
120 
121  return res;
122  }
123 
124  std::unordered_set<u32> Grouping::get_signals_of_group(u32 id, const std::unordered_map<u32, std::unordered_set<u32>>& signals) const
125  {
126  std::unordered_set<u32> res;
127 
128  for (auto gate : gates_of_group.at(id))
129  {
130  if (auto it = signals.find(gate); it != signals.end())
131  {
132  res.insert(it->second.begin(), it->second.end());
133  }
134  }
135 
136  return res;
137  }
138 
140  {
141  std::vector<u32> intersect;
142  for (auto gate : this->gates_of_group.at(id))
143  {
144  // check if gate has register_stages
145  auto it = this->netlist_abstr.gate_to_register_stages.find(gate);
146  if (it != this->netlist_abstr.gate_to_register_stages.end())
147  {
148  auto gate_rs = std::set<u32>(it->second.begin(), it->second.end());
149  if (intersect.empty())
150  {
151  intersect.insert(intersect.end(), gate_rs.begin(), gate_rs.end());
152  }
153  else
154  {
155  auto end_it = std::set_intersection(intersect.begin(), intersect.end(), gate_rs.begin(), gate_rs.end(), intersect.begin());
156  intersect.erase(end_it, intersect.end());
157  }
158 
159  if (intersect.empty())
160  {
161  break;
162  }
163  }
164  else
165  {
166  intersect.push_back(INT32_MAX);
167  }
168  }
169 
170  return std::set<u32>(intersect.begin(), intersect.end());
171  }
172 
173  std::unordered_set<u32> Grouping::get_successor_groups_of_group(u32 group_id) const
174  {
175  {
176  std::shared_lock lock(cache.mutex);
177  if (auto it = cache.suc_cache.find(group_id); it != cache.suc_cache.end())
178  {
179  return it->second;
180  }
181  }
182  std::unique_lock lock(cache.mutex);
183 
184  // check again, since another thread might have gotten the unique lock first
185  if (auto it = cache.suc_cache.find(group_id); it != cache.suc_cache.end())
186  {
187  return it->second;
188  }
189 
190  std::unordered_set<u32> successors;
191  for (auto gate : gates_of_group.at(group_id))
192  {
193  for (auto gate_id : this->netlist_abstr.gate_to_successors.at(gate))
194  {
195  successors.insert(parent_group_of_gate.at(gate_id));
196  }
197  }
198 
199  cache.suc_cache.emplace(group_id, successors);
200 
201  return successors;
202  }
203 
204  std::unordered_set<u32> Grouping::get_predecessor_groups_of_group(u32 group_id) const
205  {
206  {
207  std::shared_lock lock(cache.mutex);
208  if (auto it = cache.pred_cache.find(group_id); it != cache.pred_cache.end())
209  {
210  return it->second;
211  }
212  }
213  std::unique_lock lock(cache.mutex);
214 
215  // check again, since another thread might have gotten the unique lock first
216  if (auto it = cache.pred_cache.find(group_id); it != cache.pred_cache.end())
217  {
218  return it->second;
219  }
220 
221  std::unordered_set<u32> predecessors;
222  for (auto gate : gates_of_group.at(group_id))
223  {
224  for (auto gate_id : this->netlist_abstr.gate_to_predecessors.at(gate))
225  {
226  predecessors.insert(parent_group_of_gate.at(gate_id));
227  }
228  }
229 
230  cache.pred_cache.emplace(group_id, predecessors);
231 
232  return predecessors;
233  }
234 
235  std::unordered_set<u32> Grouping::get_known_successor_groups_of_group(u32 group_id) const
236  {
237  {
238  std::shared_lock lock(cache.mutex);
239  if (auto it = cache.suc_known_group_cache.find(group_id); it != cache.suc_known_group_cache.end())
240  {
241  return it->second;
242  }
243  }
244  std::unique_lock lock(cache.mutex);
245 
246  // check again, since another thread might have gotten the unique lock first
247  if (auto it = cache.suc_known_group_cache.find(group_id); it != cache.suc_known_group_cache.end())
248  {
249  return it->second;
250  }
251 
252  std::unordered_set<u32> successors;
253  for (auto gate : gates_of_group.at(group_id))
254  {
255  for (auto known_group_id : this->netlist_abstr.gate_to_known_successor_groups.at(gate))
256  {
257  successors.insert(known_group_id);
258  }
259  }
260 
261  cache.suc_known_group_cache.emplace(group_id, successors);
262 
263  return successors;
264  }
265 
266  std::unordered_set<u32> Grouping::get_known_predecessor_groups_of_group(u32 group_id) const
267  {
268  {
269  std::shared_lock lock(cache.mutex);
270  if (auto it = cache.pred_known_group_cache.find(group_id); it != cache.pred_known_group_cache.end())
271  {
272  return it->second;
273  }
274  }
275  std::unique_lock lock(cache.mutex);
276 
277  // check again, since another thread might have gotten the unique lock first
278  if (auto it = cache.pred_known_group_cache.find(group_id); it != cache.pred_known_group_cache.end())
279  {
280  return it->second;
281  }
282 
283  std::unordered_set<u32> predecessors;
284  for (auto gate : gates_of_group.at(group_id))
285  {
286  for (auto known_group_id : this->netlist_abstr.gate_to_known_predecessor_groups.at(gate))
287  {
288  predecessors.insert(known_group_id);
289  }
290  }
291 
292  cache.pred_known_group_cache.emplace(group_id, predecessors);
293 
294  return predecessors;
295  }
296 
297  bool Grouping::are_groups_allowed_to_merge(u32 group_1_id, u32 group_2_id, bool enforce_type_consistency) const
298  {
299  if (this->group_control_fingerprint_map.at(group_1_id) != this->group_control_fingerprint_map.at(group_2_id))
300  {
301  return false;
302  }
303  if (enforce_type_consistency
304  && (this->netlist_abstr.nl->get_gate_by_id(*gates_of_group.at(group_1_id).begin())->get_type()
305  != this->netlist_abstr.nl->get_gate_by_id(*gates_of_group.at(group_2_id).begin())->get_type()))
306  {
307  return false;
308  }
309  if (!(this->operations_on_group_allowed.at(group_1_id) && this->operations_on_group_allowed.at(group_2_id)))
310  {
311  return false;
312  }
313 
314  bool merged_allowed_register_stage = false;
315 
316  auto register_stages_group_2 = this->get_register_stage_intersect_of_group(group_2_id);
317  for (auto stage : this->get_register_stage_intersect_of_group(group_1_id))
318  {
319  if (register_stages_group_2.find(stage) != register_stages_group_2.end())
320  {
321  merged_allowed_register_stage = true;
322  break;
323  }
324  }
325  return merged_allowed_register_stage;
326  }
327 
329  {
330  if (this->operations_on_group_allowed.at(group_id))
331  {
332  return true;
333  }
334  return false;
335  }
336  } // namespace dataflow
337 } // namespace hal
GateType * get_type() const
Definition: gate.cpp:125
Gate * get_gate_by_id(const u32 gate_id) const
Definition: netlist.cpp:193
int32_t i32
Definition: defines.h:36
quint32 u32
This file contains the struct that holds all information on the netlist abstraction used for dataflow...
This file contains the class that holds all information of a dataflow analysis grouping.
Grouping used during dataflow analysis.
Definition: grouping.h:55
std::unordered_map< u32, std::vector< u32 > > group_control_fingerprint_map
Definition: grouping.h:84
std::unordered_map< u32, std::unordered_set< u32 > > gates_of_group
Definition: grouping.h:89
std::unordered_map< u32, u32 > parent_group_of_gate
Definition: grouping.h:94
std::unordered_set< u32 > get_known_predecessor_groups_of_group(u32 group_id) const
Get the known predecessor groups of a group.
Definition: grouping.cpp:266
const NetlistAbstraction & netlist_abstr
Definition: grouping.h:79
bool operator!=(const Grouping &other) const
Check two groupings for inequality.
Definition: grouping.cpp:104
std::unordered_set< u32 > get_predecessor_groups_of_group(u32 group_id) const
Get the predecessor groups of a group.
Definition: grouping.cpp:204
std::unordered_set< u32 > get_known_successor_groups_of_group(u32 group_id) const
Get the known successor groups of a group.
Definition: grouping.cpp:235
Grouping(const NetlistAbstraction &na)
Construct a new (empty) grouping from a netlist abstraction.
Definition: grouping.cpp:12
bool are_groups_allowed_to_merge(u32 group_1_id, u32 group_2_id, bool enforce_type_consistency) const
Check if two groups are allowed to be merged.
Definition: grouping.cpp:297
bool operator==(const Grouping &other) const
Check two groupings for equality.
Definition: grouping.cpp:94
std::unordered_set< u32 > get_successor_groups_of_group(u32 group_id) const
Get the successor groups of a group.
Definition: grouping.cpp:173
std::map< PinType, std::unordered_set< u32 > > get_control_signals_of_group(u32 group_id) const
Get the control signals of a group as a map from the control pin type to the connected net IDs.
Definition: grouping.cpp:109
std::set< u32 > get_register_stage_intersect_of_group(u32 group_id) const
Get the intersection of the register stages of all gates of the group.
Definition: grouping.cpp:139
std::map< u32, bool > operations_on_group_allowed
Definition: grouping.h:99
bool is_group_allowed_to_split(u32 group_id) const
Check if the group is allowed to be split.
Definition: grouping.cpp:328
The abstraction of the netlist that only contains gates of a specified type, e.g.,...
std::unordered_map< u32, std::vector< u32 > > gate_to_fingerprint
std::unordered_map< u32, std::unordered_set< u32 > > gate_to_predecessors
std::unordered_map< u32, std::map< PinType, std::unordered_set< u32 > > > gate_to_control_signals
std::unordered_map< u32, std::unordered_set< u32 > > gate_to_register_stages
std::unordered_map< u32, std::unordered_set< u32 > > gate_to_successors
std::unordered_map< u32, std::unordered_set< u32 > > gate_to_known_successor_groups
std::unordered_map< u32, std::unordered_set< u32 > > gate_to_known_predecessor_groups