Skip to content

Commit 32a395f

Browse files
committed
added caching to get_next_matching_gates
1 parent 593ce5a commit 32a395f

File tree

3 files changed

+83
-12
lines changed

3 files changed

+83
-12
lines changed

include/hal_core/netlist/decorators/netlist_traversal_decorator.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -51,42 +51,49 @@ namespace hal
5151
* Traverse over gates that do not meet the `target_gate_filter` condition.
5252
* Stop traversal if (1) `continue_on_match` is `false` the `target_gate_filter` evaluates to `true`, (2) the `exit_endpoint_filter` evaluates to `false` on a fan-in/out endpoint (i.e., when exiting the current gate during traversal), or (3) the `entry_endpoint_filter` evaluates to `false` on a successor/predecessor endpoint (i.e., when entering the next gate during traversal).
5353
* Both the `entry_endpoint_filter` and the `exit_endpoint_filter` may be omitted.
54+
* Provide a cache to speed up traversal when calling this function multiple times on the same netlist using the same forbidden pins.
55+
* Do not use a cache if the filter functions operate on the `current_depth`.
5456
*
5557
* @param[in] net - Start net.
5658
* @param[in] successors - Set `true` to get successors, set `false` to get predecessors.
5759
* @param[in] target_gate_filter - Filter condition that must be met for the target gates.
5860
* @param[in] continue_on_match - Set `true` to continue even if `target_gate_filter` evaluated to `true`, `false` otherwise. Defaults to `false`.
5961
* @param[in] exit_endpoint_filter - Filter condition that determines whether to stop traversal on a fan-in/out endpoint.
6062
* @param[in] entry_endpoint_filter - Filter condition that determines whether to stop traversal on a successor/predecessor endpoint.
63+
* @param[inout] cache - An optional cache that can be used for better performance on repeated calls. Defaults to a `nullptr`.
6164
* @returns The next gates fulfilling the target gate filter condition on success, an error otherwise.
6265
*/
6366
Result<std::set<Gate*>> get_next_matching_gates(const Net* net,
6467
bool successors,
6568
const std::function<bool(const Gate*)>& target_gate_filter,
6669
bool continue_on_match = false,
6770
const std::function<bool(const Endpoint*, const u32 current_depth)>& exit_endpoint_filter = nullptr,
68-
const std::function<bool(const Endpoint*, const u32 current_depth)>& entry_endpoint_filter = nullptr) const;
71+
const std::function<bool(const Endpoint*, const u32 current_depth)>& entry_endpoint_filter = nullptr,
72+
std::unordered_map<const Net*, std::set<Gate*>>* cache = nullptr) const;
6973

7074
/**
7175
* Starting from the given gate, traverse the netlist and return only the successor/predecessor gates for which the `target_gate_filter` evaluates to `true`.
7276
* Traverse over gates that do not meet the `target_gate_filter` condition.
7377
* Stop traversal if (1) `continue_on_match` is `false` the `target_gate_filter` evaluates to `true`, (2) the `exit_endpoint_filter` evaluates to `false` on a fan-in/out endpoint (i.e., when exiting the current gate during traversal), or (3) the `entry_endpoint_filter` evaluates to `false` on a successor/predecessor endpoint (i.e., when entering the next gate during traversal).
7478
* Both the `entry_endpoint_filter` and the `exit_endpoint_filter` may be omitted.
79+
* Do not use a cache if the filter functions operate on the `current_depth`.
7580
*
7681
* @param[in] gate - Start gate.
7782
* @param[in] successors - Set `true` to get successors, set `false` to get predecessors.
7883
* @param[in] target_gate_filter - Filter condition that must be met for the target gates.
7984
* @param[in] continue_on_match - Set `true` to continue even if `target_gate_filter` evaluated to `true`, `false` otherwise. Defaults to `false`.
8085
* @param[in] exit_endpoint_filter - Filter condition that determines whether to stop traversal on a fan-in/out endpoint.
8186
* @param[in] entry_endpoint_filter - Filter condition that determines whether to stop traversal on a successor/predecessor endpoint.
87+
* @param[inout] cache - An optional cache that can be used for better performance on repeated calls. Defaults to a `nullptr`.
8288
* @returns The next gates fulfilling the target gate filter condition on success, an error otherwise.
8389
*/
8490
Result<std::set<Gate*>> get_next_matching_gates(const Gate* gate,
8591
bool successors,
8692
const std::function<bool(const Gate*)>& target_gate_filter,
8793
bool continue_on_match = false,
8894
const std::function<bool(const Endpoint*, const u32 current_depth)>& exit_endpoint_filter = nullptr,
89-
const std::function<bool(const Endpoint*, const u32 current_depth)>& entry_endpoint_filter = nullptr) const;
95+
const std::function<bool(const Endpoint*, const u32 current_depth)>& entry_endpoint_filter = nullptr,
96+
std::unordered_map<const Net*, std::set<Gate*>>* cache = nullptr) const;
9097

9198
/**
9299
* Starting from the given net, traverse the netlist and return only the successor/predecessor gates for which the `target_gate_filter` evaluates to `true`.

src/netlist/decorators/netlist_traversal_decorator.cpp

+56-10
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ namespace hal
1414
const std::function<bool(const Gate*)>& target_gate_filter,
1515
bool continue_on_match,
1616
const std::function<bool(const Endpoint*, u32 current_depth)>& exit_endpoint_filter,
17-
const std::function<bool(const Endpoint*, u32 current_depth)>& entry_endpoint_filter) const
17+
const std::function<bool(const Endpoint*, u32 current_depth)>& entry_endpoint_filter,
18+
std::unordered_map<const Net*, std::set<Gate*>>* cache) const
1819
{
1920
if (net == nullptr)
2021
{
@@ -56,29 +57,59 @@ namespace hal
5657
continue;
5758
}
5859

59-
auto* g = entry_ep->get_gate();
60+
auto* gate = entry_ep->get_gate();
6061

61-
if (target_gate_filter(g))
62+
if (target_gate_filter(gate))
6263
{
63-
res.insert(g);
64+
res.insert(gate);
65+
66+
// update cache
67+
if (cache)
68+
{
69+
(*cache)[current].insert(gate);
70+
for (const auto* n : previous)
71+
{
72+
(*cache)[n].insert(gate);
73+
}
74+
}
6475

6576
if (!continue_on_match)
6677
{
6778
continue;
6879
}
6980
}
7081

71-
for (const auto* exit_ep : successors ? g->get_fan_out_endpoints() : g->get_fan_in_endpoints())
82+
for (const auto* exit_ep : successors ? gate->get_fan_out_endpoints() : gate->get_fan_in_endpoints())
7283
{
7384
if (exit_endpoint_filter != nullptr && !exit_endpoint_filter(exit_ep, previous.size() + 1))
7485
{
7586
continue;
7687
}
7788

78-
const Net* n = exit_ep->get_net();
79-
if (visited.find(n) == visited.end())
89+
const Net* exit_net = exit_ep->get_net();
90+
if (cache)
8091
{
81-
stack.push_back(n);
92+
if (const auto it = cache->find(exit_net); it != cache->end())
93+
{
94+
const auto& cached_gates = std::get<1>(*it);
95+
96+
// append cached gates to result
97+
res.insert(cached_gates.begin(), cached_gates.end());
98+
99+
// update cache
100+
(*cache)[current].insert(cached_gates.begin(), cached_gates.end());
101+
for (const auto* n : previous)
102+
{
103+
(*cache)[n].insert(cached_gates.begin(), cached_gates.end());
104+
}
105+
106+
continue;
107+
}
108+
}
109+
110+
if (visited.find(exit_net) == visited.end())
111+
{
112+
stack.push_back(exit_net);
82113
added = true;
83114
}
84115
}
@@ -102,7 +133,8 @@ namespace hal
102133
const std::function<bool(const Gate*)>& target_gate_filter,
103134
bool continue_on_match,
104135
const std::function<bool(const Endpoint*, u32 current_depth)>& exit_endpoint_filter,
105-
const std::function<bool(const Endpoint*, u32 current_depth)>& entry_endpoint_filter) const
136+
const std::function<bool(const Endpoint*, u32 current_depth)>& entry_endpoint_filter,
137+
std::unordered_map<const Net*, std::set<Gate*>>* cache) const
106138
{
107139
if (gate == nullptr)
108140
{
@@ -122,7 +154,21 @@ namespace hal
122154
continue;
123155
}
124156

125-
const auto next_res = this->get_next_matching_gates(exit_ep->get_net(), successors, target_gate_filter, continue_on_match, exit_endpoint_filter, entry_endpoint_filter);
157+
const auto* exit_net = exit_ep->get_net();
158+
if (cache)
159+
{
160+
if (const auto it = cache->find(exit_net); it != cache->end())
161+
{
162+
const auto& cached_gates = std::get<1>(*it);
163+
164+
// append cached gates to result
165+
res.insert(cached_gates.begin(), cached_gates.end());
166+
167+
continue;
168+
}
169+
}
170+
171+
const auto next_res = this->get_next_matching_gates(exit_net, successors, target_gate_filter, continue_on_match, exit_endpoint_filter, entry_endpoint_filter, cache);
126172
if (next_res.is_error())
127173
{
128174
return ERR(next_res.get_error());

tests/netlist/decorators.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,15 @@ namespace hal {
672672
EXPECT_TRUE(res.is_ok());
673673
EXPECT_EQ(res.get(), std::set<Gate*>({dff4, dff5, dff6}));
674674
}
675+
{
676+
std::unordered_map<const Net*, std::set<Gate*>> cache;
677+
const auto res1 = trav_dec.get_next_matching_gates(dff2, true, [](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::ff); }, false, nullptr, nullptr, &cache);
678+
EXPECT_TRUE(res1.is_ok());
679+
EXPECT_EQ(res1.get(), std::set<Gate*>({dff5, dff6, dff7, dff3}));
680+
const auto res2 = trav_dec.get_next_matching_gates(dff3, true, [](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::ff); }, false, nullptr, nullptr, &cache);
681+
EXPECT_TRUE(res2.is_ok());
682+
EXPECT_EQ(res2.get(), std::set<Gate*>({dff6, dff7, dff3}));
683+
}
675684

676685
// predecessors
677686
{
@@ -684,6 +693,15 @@ namespace hal {
684693
EXPECT_TRUE(res.is_ok());
685694
EXPECT_EQ(res.get(), std::set<Gate*>({dff0, dff1, dff2}));
686695
}
696+
{
697+
std::unordered_map<const Net*, std::set<Gate*>> cache;
698+
const auto res1 = trav_dec.get_next_matching_gates(dff6, false, [](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::ff); }, false, nullptr, nullptr, &cache);
699+
EXPECT_TRUE(res1.is_ok());
700+
EXPECT_EQ(res1.get(), std::set<Gate*>({dff1, dff2, dff3, sff0, sff1}));
701+
const auto res2 = trav_dec.get_next_matching_gates(dff7, false, [](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::ff); }, false, nullptr, nullptr, &cache);
702+
EXPECT_TRUE(res2.is_ok());
703+
EXPECT_EQ(res2.get(), std::set<Gate*>({dff2, dff3, sff0, sff1}));
704+
}
687705
}
688706
{
689707
// test NetlistModificationDecorator::get_next_matching_gates_until

0 commit comments

Comments
 (0)