Skip to content

Commit fe64f81

Browse files
authored
Merge pull request #8073 from The-OpenROAD-Project-staging/secure-fix-find-instances-matching
dbSta: Enabled multi-level hierarchical path search for get_cells/get_pins/get_nets
2 parents 32174f7 + 9c6bce7 commit fe64f81

File tree

7 files changed

+145
-7
lines changed

7 files changed

+145
-7
lines changed

src/dbSta/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ cc_library(
3535
"//src/sta:opensta_lib",
3636
"//src/utl",
3737
"@boost.json",
38+
"@spdlog",
3839
"@tk_tcl//:tcl",
3940
],
4041
)

src/dbSta/src/dbSdcNetwork.cc

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33

44
#include "dbSdcNetwork.hh"
55

6+
#include <spdlog/fmt/fmt.h>
7+
68
#include <memory>
79
#include <string>
10+
#include <string_view>
811

912
#include "sta/ParseBus.hh"
1013
#include "sta/PatternMatch.hh"
@@ -62,14 +65,47 @@ InstanceSeq dbSdcNetwork::findInstancesMatching(
6265
void dbSdcNetwork::findInstancesMatching1(const PatternMatch* pattern,
6366
InstanceSeq& insts) const
6467
{
65-
std::unique_ptr<InstanceChildIterator> child_iter{
66-
childIterator(topInstance())};
67-
while (child_iter->hasNext()) {
68-
Instance* child = child_iter->next();
69-
if (pattern->match(staToSdc(name(child)))) {
70-
insts.push_back(child);
68+
// A recursive lambda to traverse the design hierarchy with a depth-first
69+
// search (DFS).
70+
// It builds the hierarchical path incrementally using fmt::memory_buffer to
71+
// avoid expensive std::string allocations and copies at each step.
72+
std::function<void(Instance*, fmt::memory_buffer&)> dfs_search
73+
= [&, this](Instance* instance, fmt::memory_buffer& path_buffer) -> void {
74+
// Iterate over the children of the current instance.
75+
std::unique_ptr<InstanceChildIterator> child_iter{childIterator(instance)};
76+
while (child_iter->hasNext()) {
77+
Instance* child = child_iter->next();
78+
79+
// Save the current size of the buffer to restore it later.
80+
const size_t original_size = path_buffer.size();
81+
82+
// Build the child's full path name incrementally.
83+
if (original_size > 0) {
84+
path_buffer.push_back(pathDivider());
85+
}
86+
path_buffer.append(std::string_view(name(child)));
87+
88+
// Check if the child instance name matches the pattern.
89+
// Add a null terminator for C-style string compatibility.
90+
path_buffer.push_back('\0');
91+
if (pattern->match(staToSdc(path_buffer.data()))) {
92+
insts.push_back(child);
93+
}
94+
path_buffer.resize(path_buffer.size() - 1); // Remove the null terminator
95+
96+
// Recurse into the child's hierarchy if it's not a leaf.
97+
if (!isLeaf(child)) {
98+
dfs_search(child, path_buffer);
99+
}
100+
101+
// Restore the buffer to its original state for the next sibling.
102+
path_buffer.resize(original_size);
71103
}
72-
}
104+
};
105+
106+
// Start the search from the top-level instance.
107+
fmt::memory_buffer path_buffer;
108+
dfs_search(topInstance(), path_buffer);
73109
}
74110

75111
NetSeq dbSdcNetwork::findNetsMatching(const Instance*,

src/dbSta/test/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ COMPULSORY_TESTS = [
1414
"hier2",
1515
"hierclock",
1616
"hierwrite",
17+
"hier_deep",
1718
"make_port",
1819
"network_edit1",
1920
"power1",
@@ -117,6 +118,7 @@ filegroup(
117118
"hier2_out.vok",
118119
"hierclock_gate.v",
119120
"hierclock_out.vok",
121+
"hier_deep.v",
120122
"liberty1.lef",
121123
"liberty1.lib",
122124
"pad.lef",

src/dbSta/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ or_integration_tests(
1212
hier2
1313
hierclock
1414
hierwrite
15+
hier_deep
1516
make_port
1617
network_edit1
1718
power1

src/dbSta/test/hier_deep.ok

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
[INFO ODB-0227] LEF file: example1.lef, created 2 layers, 6 library cells
2+
[WARNING ORD-0011] Hierarchical flow (-hier) is currently in development and may cause multiple issues. Do not use in production environments.
3+
cmd: get_cells level1_inst
4+
count: 1
5+
level1_inst
6+
----------------------
7+
cmd: get_cells level1_inst/level2_inst
8+
count: 1
9+
level1_inst/level2_inst
10+
----------------------
11+
cmd: get_cells level1_inst/level2_inst/leaf_inst
12+
count: 1
13+
level1_inst/level2_inst/leaf_inst
14+
----------------------
15+
cmd: get_cells level1_inst/level2_inst/leaf_inst/inverter
16+
count: 1
17+
level1_inst/level2_inst/leaf_inst/inverter
18+
----------------------
19+
cmd: get_cells level1_*
20+
count: 4
21+
level1_inst
22+
level1_inst/level2_inst
23+
level1_inst/level2_inst/leaf_inst
24+
level1_inst/level2_inst/leaf_inst/inverter
25+
----------------------
26+
cmd: get_cells *level2*
27+
count: 3
28+
level1_inst/level2_inst
29+
level1_inst/level2_inst/leaf_inst
30+
level1_inst/level2_inst/leaf_inst/inverter
31+
----------------------
32+
cmd: get_cells *leaf*
33+
count: 2
34+
level1_inst/level2_inst/leaf_inst
35+
level1_inst/level2_inst/leaf_inst/inverter
36+
----------------------
37+
cmd: get_cells *inv*
38+
count: 1
39+
level1_inst/level2_inst/leaf_inst/inverter
40+
----------------------
41+
cmd: get_cells */level2*inv*
42+
count: 1
43+
level1_inst/level2_inst/leaf_inst/inverter
44+
----------------------

src/dbSta/test/hier_deep.tcl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
source "helpers.tcl"
2+
read_lef example1.lef
3+
read_liberty example1_typ.lib
4+
read_verilog hier_deep.v
5+
link_design top -hier
6+
7+
proc test_get_cells { pattern } {
8+
set cells [get_cells $pattern]
9+
puts "cmd: get_cells $pattern"
10+
puts "count: [llength $cells]"
11+
foreach cell $cells {
12+
puts [get_full_name $cell]
13+
}
14+
puts "----------------------"
15+
}
16+
17+
test_get_cells "level1_inst"
18+
test_get_cells "level1_inst/level2_inst"
19+
test_get_cells "level1_inst/level2_inst/leaf_inst"
20+
test_get_cells "level1_inst/level2_inst/leaf_inst/inverter"
21+
22+
test_get_cells "level1_*"
23+
test_get_cells "*level2*"
24+
test_get_cells "*leaf*"
25+
test_get_cells "*inv*"
26+
test_get_cells "*/level2*inv*"

src/dbSta/test/hier_deep.v

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
lef: example1.lef
3+
lib: example1_typ.lib
4+
*/
5+
6+
module leaf (a, z);
7+
input a;
8+
output z;
9+
INV_X1 inverter (.A(a), .ZN(z));
10+
endmodule
11+
12+
module level2 (in, out);
13+
input in;
14+
output out;
15+
leaf leaf_inst (.a(in), .z(out));
16+
endmodule
17+
18+
module level1 (in, out);
19+
input in;
20+
output out;
21+
level2 level2_inst (.in(in), .out(out));
22+
endmodule
23+
24+
module top (a, b);
25+
input a;
26+
output b;
27+
level1 level1_inst (.in(a), .out(b));
28+
endmodule

0 commit comments

Comments
 (0)