Skip to content
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
615bd5a
[lib][rr_graph] initial impl for remove node
amin1377 Nov 17, 2025
511f89d
[libs][rr_graph] uniquify remove edges
amin1377 Nov 17, 2025
112a6c0
Merge branch 'rr_graph_interposer_cut' of https://github.com/verilog-…
amin1377 Nov 17, 2025
5bbf3d7
[lib][rr_graph] add comments + shrink rr graph node data structures
amin1377 Nov 17, 2025
dfc2a33
fix a typo
amin1377 Nov 17, 2025
ec0a8e5
[lib][rr_graph] remove node_tilable_track_nums_ from rr graph builder
amin1377 Nov 17, 2025
7817922
[lib][rr_graph] add node_tilable_track_nums_ to rr graph storage
amin1377 Nov 17, 2025
54ff743
[lib][rr_grpah] remove node_tileable_track_nums_ from rr_graph_view
amin1377 Nov 17, 2025
3da38b0
[lib][librrgraph] set tileable to true when reading rr graph from a f…
amin1377 Nov 17, 2025
dda1dd5
[libs][rrgraph] remove redundant function call
amin1377 Nov 17, 2025
de52b91
[vpr] fix instances of rr graph view
amin1377 Nov 17, 2025
4830963
[lib][rr_graph] add remove_node header
amin1377 Nov 17, 2025
3b9f552
[lib][rr_graph] erase node_tilable_track_nums_ when removing a node
amin1377 Nov 17, 2025
5f49e17
Merge branch 'rr_graph_interposer_cut' of https://github.com/verilog-…
amin1377 Nov 17, 2025
99e40a2
Merge branch 'master' of https://github.com/verilog-to-routing/vtr-ve…
amin1377 Nov 20, 2025
ec9b088
Merge branch 'rr_graph_interposer_cut' of https://github.com/verilog-…
amin1377 Nov 20, 2025
e5a0f13
[lib][rr_graph][storage] fix bugs with remove_nodes
amin1377 Nov 20, 2025
513115d
Merge branch 'master' of https://github.com/verilog-to-routing/vtr-ve…
amin1377 Nov 20, 2025
10a876a
Merge branch 'master' of https://github.com/verilog-to-routing/vtr-ve…
amin1377 Nov 21, 2025
52637f2
Merge branch 'master' of https://github.com/verilog-to-routing/vtr-ve…
amin1377 Nov 21, 2025
684c864
[ci] update flat router results based on extracted results from ci
amin1377 Nov 21, 2025
4a05ac1
Merge branch 'master' of https://github.com/verilog-to-routing/vtr-ve…
amin1377 Nov 24, 2025
cf49863
[lib][rr_graph] apply comments for rr_graph_storage
amin1377 Nov 24, 2025
7129eda
[lib][rr_graph] pass vector of ptc nums to set_node_ptc_nums and add …
amin1377 Nov 24, 2025
955502d
[lib][rr_graph] fix node_offset check in add_node_tilable_track_num
amin1377 Nov 24, 2025
3c7b677
[lib][rr_graph] add node_ptc_number_to_string
amin1377 Nov 24, 2025
79694d3
[lib][rr_graph] remove ptc_to_string from rr_graph_builder
amin1377 Nov 24, 2025
6dfc2c3
[lib][rr_graph] add comments
amin1377 Nov 24, 2025
838d5f9
[lib][rr_graph] fix iterator idx
amin1377 Nov 24, 2025
20fde60
fix a typo
amin1377 Nov 24, 2025
d5a5555
[ci] update flat router golden result
amin1377 Nov 24, 2025
167a46c
[lib][rr_graph] remove unlock_storage
amin1377 Nov 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 8 additions & 51 deletions libs/librrgraph/src/base/rr_graph_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ vtr::vector<RRNodeId, std::vector<RREdgeId>>& RRGraphBuilder::node_in_edge_stora
return node_in_edges_;
}

vtr::vector<RRNodeId, std::vector<short>>& RRGraphBuilder::node_ptc_storage() {
return node_tilable_track_nums_;
}

void RRGraphBuilder::add_node_to_all_locs(RRNodeId node) {
e_rr_type node_type = node_storage_.node_type(node);
short node_ptc_num = node_storage_.node_ptc_num(node);
Expand Down Expand Up @@ -76,7 +72,6 @@ RRNodeId RRGraphBuilder::create_node(int layer, int x, int y, e_rr_type type, in
node_side = side;
}
node_storage_.emplace_back();
node_tilable_track_nums_.emplace_back();
RRNodeId new_node = RRNodeId(node_storage_.size() - 1);
node_storage_.set_node_layer(new_node, layer, layer);
node_storage_.set_node_type(new_node, type);
Expand All @@ -102,7 +97,6 @@ void RRGraphBuilder::clear() {
node_lookup_.clear();
node_storage_.clear();
node_in_edges_.clear();
node_tilable_track_nums_.clear();
rr_node_metadata_.clear();
rr_edge_metadata_.clear();
rr_segments_.clear();
Expand Down Expand Up @@ -232,58 +226,20 @@ std::vector<RREdgeId> RRGraphBuilder::node_in_edges(RRNodeId node) const {
}

void RRGraphBuilder::set_node_ptc_nums(RRNodeId node, const std::string& ptc_str) {
VTR_ASSERT(size_t(node) < node_storage_.size());
std::vector<std::string> ptc_tokens = vtr::StringToken(ptc_str).split(",");
VTR_ASSERT(ptc_tokens.size() >= 1);
set_node_ptc_num(node, std::stoi(ptc_tokens[0]));
if (ptc_tokens.size() > 1) {
VTR_ASSERT(size_t(node) < node_tilable_track_nums_.size());
node_tilable_track_nums_[node].resize(ptc_tokens.size());
for (size_t iptc = 0; iptc < ptc_tokens.size(); iptc++) {
node_tilable_track_nums_[node][iptc] = std::stoi(ptc_tokens[iptc]);
}
}
node_storage_.set_node_ptc_nums(node, ptc_str);
}

std::string RRGraphBuilder::node_ptc_nums_to_string(RRNodeId node) const {
if (node_tilable_track_nums_.empty()) {
return std::to_string(size_t(node_storage_.node_ptc_num(node)));
}
VTR_ASSERT(size_t(node) < node_tilable_track_nums_.size());
if (node_tilable_track_nums_[node].empty()) {
return std::to_string(size_t(node_storage_.node_ptc_num(node)));
}
std::string ret;
for (size_t iptc = 0; iptc < node_tilable_track_nums_[node].size(); iptc++) {
ret += std::to_string(size_t(node_tilable_track_nums_[node][iptc])) + ",";
}
// Remove the last comma
ret.pop_back();
return ret;
return node_storage_.node_ptc_nums_to_string(node);
}

bool RRGraphBuilder::node_contain_multiple_ptc(RRNodeId node) const {
if (node_tilable_track_nums_.empty()) {
return false;
}
return node_tilable_track_nums_[node].size() > 1;
return node_storage_.node_contain_multiple_ptc(node);
}

void RRGraphBuilder::add_node_track_num(RRNodeId node, vtr::Point<size_t> node_offset, short track_id) {
VTR_ASSERT(size_t(node) < node_storage_.size());
VTR_ASSERT(size_t(node) < node_tilable_track_nums_.size());
VTR_ASSERT_MSG(node_storage_.node_type(node) == e_rr_type::CHANX || node_storage_.node_type(node) == e_rr_type::CHANY, "Track number valid only for CHANX/CHANY RR nodes");

size_t node_length = std::abs(node_storage_.node_xhigh(node) - node_storage_.node_xlow(node))
+ std::abs(node_storage_.node_yhigh(node) - node_storage_.node_ylow(node));
if (node_length + 1 != node_tilable_track_nums_[node].size()) {
node_tilable_track_nums_[node].resize(node_length + 1);
}

size_t offset = node_offset.x() - node_storage_.node_xlow(node) + node_offset.y() - node_storage_.node_ylow(node);
VTR_ASSERT(offset < node_tilable_track_nums_[node].size());

node_tilable_track_nums_[node][offset] = track_id;
size_t node_offset_value = node_offset.x() - node_storage_.node_xlow(node) + node_offset.y() - node_storage_.node_ylow(node);
node_storage_.add_node_tilable_track_num(node, node_offset_value, track_id);
}

void RRGraphBuilder::add_track_node_to_lookup(RRNodeId node) {
Expand All @@ -309,8 +265,9 @@ void RRGraphBuilder::add_track_node_to_lookup(RRNodeId node) {
// Routing channel nodes may have different ptc num
// Find the track ids using the x/y offset
if (e_rr_type::CHANX == node_type || e_rr_type::CHANY == node_type) {
ptc = (node_type == e_rr_type::CHANX) ? node_tilable_track_nums_[node][x - node_storage_.node_xlow(node)] :
node_tilable_track_nums_[node][y - node_storage_.node_ylow(node)];
const std::vector<short>& track_nums = node_storage_.node_tilable_track_nums(node);
ptc = (node_type == e_rr_type::CHANX) ? track_nums[x - node_storage_.node_xlow(node)] :
track_nums[y - node_storage_.node_ylow(node)];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't like the way the ternary operator is used here. We have an assertion at the beginning of this function is CHANX or CHANY, so I think we could do something like:

ptc_num = undefined
if (chanx) ptc_num = something
else if (chany) ptc_num = something_else
add_node

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I applied the change you requested. But just out of curiosity, what’s the issue with using the ternary operator?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just very hard to read if the statements aren't super short and trivial imo.

node_lookup_.add_node(node, node_storage_.node_layer_low(node), x, y, node_type, ptc);
}
}
Expand Down
30 changes: 0 additions & 30 deletions libs/librrgraph/src/base/rr_graph_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ class RRGraphBuilder {

/** @brief Return a writable object for the incoming edge storage */
vtr::vector<RRNodeId, std::vector<RREdgeId>>& node_in_edge_storage();

/** @brief Return a writable object of the node ptc storage (for tileable routing resource graph) */
vtr::vector<RRNodeId, std::vector<short>>& node_ptc_storage();

/** @brief Return the size for rr_node_metadata */
inline size_t rr_node_metadata_size() const {
Expand Down Expand Up @@ -432,10 +429,6 @@ class RRGraphBuilder {
inline void resize_nodes(size_t size) {
node_storage_.resize(size);
}
/** @brief This function resize node ptc nums. Only used by RR graph I/O reader and writers. */
inline void resize_node_ptc_nums(size_t size) {
node_tilable_track_nums_.resize(size);
}


/** @brief This function resize rr_switch to accommodate size RR Switch. */
Expand Down Expand Up @@ -539,29 +532,6 @@ class RRGraphBuilder {
*/
vtr::vector<RRNodeId, std::vector<RREdgeId>> node_in_edges_;

/**
* @brief Extra ptc number for each routing resource node.
* @note This is required by tileable routing resource graphs. The first index is the node id, and
* the second index is is the relative distance from the starting point of the node.
* @details
* In a tileable routing architecture, routing tracks, e.g., CHANX and CHANY, follow a staggered organization.
* Hence, a routing track may appear in different routing channels, representing different ptc/track id.
* Here is an illustrative example of a X-direction routing track (CHANX) in INC direction, which is organized in staggered way.
*
* Coord(x,y) (1,0) (2,0) (3,0) (4,0) Another track (node)
* ptc=0 ------> ------>
* \ /
* ptc=1 ------> /
* \ /
* ptc=2 ------> /
* \ /
* ptc=3 ------->
* ^ ^
* | |
* starting point ending point
*/
vtr::vector<RRNodeId, std::vector<short>> node_tilable_track_nums_;

/** @warning The Metadata should stay as an independent data structure from the rest of the internal data,
* e.g., node_lookup! */
/* Metadata is an extra data on rr-nodes and edges, respectively, that is not used by vpr
Expand Down
128 changes: 127 additions & 1 deletion libs/librrgraph/src/base/rr_graph_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ void t_rr_graph_storage::alloc_and_load_edges(const t_rr_edge_info_set* rr_edges
void t_rr_graph_storage::remove_edges(std::vector<RREdgeId>& rr_edges_to_remove) {
VTR_ASSERT(!edges_read_);

if (rr_edges_to_remove.empty()) {
return;
}

size_t starting_edge_count = edge_dest_node_.size();

// Sort and make sure all edge indices are unique
Expand Down Expand Up @@ -178,7 +182,7 @@ bool t_rr_graph_storage::verify_first_edges() const {

void t_rr_graph_storage::init_fan_in() {
//Reset all fan-ins to zero
edges_read_ = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this method shouldn't set this flag, but I think I need a couple more eyes to look at this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@soheilshahrouz: If you get a chance, I’d appreciate your thoughts on this. The reason I believe this needs to be removed is that edge_read should only be set when we are modifying data structures related to RR edges; for example, when updating edge_sink_node_ or the data structure that stores the first edge for each node.

In this case, we are only modifying the data structure that tracks the number of fan-ins for each node, and I should be able to call this without requiring edge_read to be set to true (since that would imply that edges must have been partitioned, etc.).

node_fan_in_.clear();
node_fan_in_.resize(node_storage_.size(), 0);
node_fan_in_.shrink_to_fit();
//Walk the graph and increment fanin on all downstream nodes
Expand Down Expand Up @@ -625,6 +629,54 @@ void t_rr_graph_storage::set_node_direction(RRNodeId id, Direction new_direction
node_storage_[id].dir_side_.direction = new_direction;
}

void t_rr_graph_storage::set_node_ptc_nums(RRNodeId node, const std::string& ptc_str) {
VTR_ASSERT(size_t(node) < node_storage_.size());
std::vector<std::string> ptc_tokens = vtr::StringToken(ptc_str).split(",");
VTR_ASSERT(ptc_tokens.size() >= 1);
set_node_ptc_num(node, std::stoi(ptc_tokens[0]));
if (ptc_tokens.size() > 1) {
VTR_ASSERT(size_t(node) < node_tilable_track_nums_.size());
node_tilable_track_nums_[node].resize(ptc_tokens.size());
for (size_t iptc = 0; iptc < ptc_tokens.size(); iptc++) {
node_tilable_track_nums_[node][iptc] = std::stoi(ptc_tokens[iptc]);
}
}
}

void t_rr_graph_storage::add_node_tilable_track_num(RRNodeId node, size_t node_offset, short track_id) {
VTR_ASSERT(size_t(node) < node_storage_.size());
VTR_ASSERT(size_t(node) < node_tilable_track_nums_.size());
VTR_ASSERT_MSG(node_type(node) == e_rr_type::CHANX || node_type(node) == e_rr_type::CHANY,
"Track number valid only for CHANX/CHANY RR nodes");

size_t node_length = std::abs(node_xhigh(node) - node_xlow(node))
+ std::abs(node_yhigh(node) - node_ylow(node));
if (node_length + 1 != node_tilable_track_nums_[node].size()) {
node_tilable_track_nums_[node].resize(node_length + 1);
}

VTR_ASSERT(node_offset < node_tilable_track_nums_[node].size());

node_tilable_track_nums_[node][node_offset] = track_id;
}

std::string t_rr_graph_storage::node_ptc_nums_to_string(RRNodeId node) const {
if (node_tilable_track_nums_.empty()) {
return std::to_string(size_t(node_ptc_num(node)));
}
VTR_ASSERT(size_t(node) < node_tilable_track_nums_.size());
if (node_tilable_track_nums_[node].empty()) {
return std::to_string(size_t(node_ptc_num(node)));
}
std::string ret;
for (size_t iptc = 0; iptc < node_tilable_track_nums_[node].size(); iptc++) {
ret += std::to_string(size_t(node_tilable_track_nums_[node][iptc])) + ",";
}
// Remove the last comma
ret.pop_back();
return ret;
}

void t_rr_graph_storage::add_node_side(RRNodeId id, e_side new_side) {
if (node_type(id) != e_rr_type::IPIN && node_type(id) != e_rr_type::OPIN) {
VTR_LOG_ERROR("Attempted to set RR node 'side' for non-pin type '%s'", node_type_string(id));
Expand All @@ -651,6 +703,80 @@ void t_rr_graph_storage::set_virtual_clock_network_root_idx(RRNodeId virtual_clo
}
}

void t_rr_graph_storage::remove_nodes(const std::vector<RRNodeId>& nodes) {
VTR_ASSERT(!edges_read_);
// To remove the nodes, we first sort them in ascending order. This makes it easy
// to calculate the offset by which other node IDs need to be adjusted.
// For example, after sorting the nodes to be removed, if a node ID falls between
// the first and second element, its ID should be reduced by 1.
// If a node ID is larger than the last element, its ID should be reduced by
// the total number of nodes being removed.
std::vector<RRNodeId> sorted_nodes = nodes;
std::sort(sorted_nodes.begin(), sorted_nodes.end());

// Iterate over the nodes to be removed and adjust the IDs of nodes
// that fall between them.
for (size_t i = 0; i < sorted_nodes.size(); ++i) {
size_t start_rr_node_index = size_t(sorted_nodes[i]) + 1;
size_t end_rr_node_index = (i == sorted_nodes.size() - 1) ? node_storage_.size() : size_t(sorted_nodes[i + 1]);
for (size_t j = start_rr_node_index; j < end_rr_node_index; ++j) {
RRNodeId old_node = RRNodeId(j);
// New node index is equal to the old nodex index minus the number of nodes being removed before it.
RRNodeId new_node = RRNodeId(j-(i+1));
node_storage_[new_node] = node_storage_[old_node];
node_ptc_[new_node] = node_ptc_[old_node];
node_layer_[new_node] = node_layer_[old_node];
node_name_[new_node] = node_name_[old_node];
if (is_tileable_) {
node_bend_start_[new_node] = node_bend_start_[old_node];
node_bend_end_[new_node] = node_bend_end_[old_node];
node_tilable_track_nums_[new_node] = node_tilable_track_nums_[old_node];
}
}
}

// Now that the data structures are adjusted, we can shrink the size of them
size_t num_nodes_to_remove = sorted_nodes.size();
VTR_ASSERT(num_nodes_to_remove <= node_storage_.size());
node_storage_.erase(node_storage_.end()-num_nodes_to_remove, node_storage_.end());
node_ptc_.erase(node_ptc_.end()-num_nodes_to_remove, node_ptc_.end());
node_layer_.erase(node_layer_.end()-num_nodes_to_remove, node_layer_.end());
for (size_t node_index = node_name_.size()-num_nodes_to_remove; node_index < node_name_.size(); ++node_index) {
RRNodeId node = RRNodeId(node_index);
node_name_.erase(node);
}
if (is_tileable_) {
node_bend_start_.erase(node_bend_start_.end()-num_nodes_to_remove, node_bend_start_.end());
node_bend_end_.erase(node_bend_end_.end()-num_nodes_to_remove, node_bend_end_.end());
node_tilable_track_nums_.erase(node_tilable_track_nums_.end()-num_nodes_to_remove, node_tilable_track_nums_.end());
}

std::vector<RREdgeId> removed_edges;
auto adjust_edges = [&](vtr::vector<RREdgeId, RRNodeId>& edge_nodes) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please explicitly add the variables you want to the capture list.

for (size_t edge_index = 0; edge_index < edge_nodes.size(); ++edge_index) {
RREdgeId edge_id = RREdgeId(edge_index);
Comment on lines +754 to +755
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use all_edges() instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m iterating over the vector that’s passed to the lambda function… I think I’m not fully understanding what you mean here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh okay didn't see that, sorry. Why not iterate over .pairs() then?

for (auto [edge_id, node] : edge_nodes.pairs())

This is a very minor nitpick tbh, I just don't like the cast. Feel free to ignore if you disagree.

RRNodeId node = edge_nodes[edge_id];

// Find insertion point in the sorted vector
auto node_it = std::lower_bound(sorted_nodes.begin(), sorted_nodes.end(), node);

if (node_it != sorted_nodes.end() && *node_it == node) {
// Node exists in sorted_nodes, mark edge for removal
removed_edges.push_back(edge_id);
} else {
size_t node_offset = std::distance(sorted_nodes.begin(), node_it);
size_t new_node_index = size_t(node) - node_offset;
edge_nodes[edge_id] = RRNodeId(new_node_index);
}
}
};

adjust_edges(edge_src_node_);
adjust_edges(edge_dest_node_);

remove_edges(removed_edges);
}

int t_rr_graph_view::node_ptc_num(RRNodeId id) const {
return node_ptc_[id].ptc_.pin_num;
}
Expand Down
Loading
Loading