Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 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
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)];
Comment on lines 267 to +270
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

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.

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(",");
Copy link
Contributor

Choose a reason for hiding this comment

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

This method (and the corresponding method in RRGraphBuilder should get a nice, parsed vector of ints instead of parsing the string themselves. As of now this method is doing way too many things. Whoever calls this method should do the parsing themselves.

VTR_ASSERT(ptc_tokens.size() >= 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

VTR_ASSERT(!ptc_tokens.empty());

set_node_ptc_num(node, std::stoi(ptc_tokens[0]));
Copy link
Contributor

Choose a reason for hiding this comment

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

Add comment explaining why the first ptc_num is stored somewhere, then all ptc_nums are stored in another place. Why do we have this duplication?

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());
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this would be clearer if it compared node_offset with node_length (can't have an offset bigger that's bigger than how long the node actually is) and it was before resizing node_tilable_track_nums_ (after line 653).


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;
}
Comment on lines +663 to +678
Copy link
Contributor

Choose a reason for hiding this comment

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

t_rr_graph_storage (and RRGraphBuilder) should not be doing string manipulations at all. I would move this to a free helper function in rr_graph_utils which takes a node ID and a reference to RRGraphView.


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) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Rename "nodes" to something like "rr_nodes_to_remove"

VTR_ASSERT(!edges_read_);
Copy link
Contributor

Choose a reason for hiding this comment

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

Add assertion for edges_partitioned_

// 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;
Copy link
Contributor

Choose a reason for hiding this comment

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

This should also be renamed accordingly.

std::sort(sorted_nodes.begin(), sorted_nodes.end());
Comment on lines +714 to +715
Copy link
Contributor

Choose a reason for hiding this comment

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

How much do you care about not mutating the list of nodes for removal? This copy seems unnecessary to me but it's your call.


// 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) {
Copy link
Contributor

Choose a reason for hiding this comment

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

i and j are very vague. Maybe something like "removal_index" and "node_index" would be clearer? Not sure.

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];
}
}
}
Comment on lines +719 to +736
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks sound from what I can see be we should definitely have a CI test that uses this function.


// 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);
}
Comment on lines +744 to +747
Copy link
Contributor

Choose a reason for hiding this comment

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

Add comment explaining why this is correct (node_name is a hashmap not a vector and all the RRNodeIds past #nodes - #removal_nodes are invalid)

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

Add a comment explaining what this lambda does.

for (size_t edge_index = 0; edge_index < edge_nodes.size(); ++edge_index) {
RREdgeId edge_id = RREdgeId(edge_index);
Comment on lines +756 to +757
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.

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);
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure what's going on here. A comment would be nice.

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_);
Comment on lines +774 to +775
Copy link
Contributor

Choose a reason for hiding this comment

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

What about edge_switch_ and edge_remapped_?


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