From fb0bcd7a48dd1f70d1ad47c99edf13a8509cdead Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 31 Jan 2020 12:29:50 -0700 Subject: [PATCH] create rr_graph library to enforce unit test on the new data structures as well as compare to legacy rr_node --- libs/CMakeLists.txt | 1 + libs/librrgraph/CMakeLists.txt | 35 + .../librrgraph/src}/check_rr_graph_obj.cpp | 19 +- .../librrgraph/src}/check_rr_graph_obj.h | 0 .../librrgraph/src}/rr_graph_fwd.h | 0 .../librrgraph/src}/rr_graph_obj.cpp | 631 ++++++++++-------- .../librrgraph/src}/rr_graph_obj.h | 171 +++-- .../librrgraph/src}/rr_graph_obj_utils.h | 26 + libs/librrgraph/src/rr_graph_types.h | 43 ++ .../librrgraph/src}/rr_graph_util.cpp | 0 .../librrgraph/src}/rr_graph_util.h | 0 libs/librrgraph/test/test_rr_graph.cpp | 8 + libs/libvtrutil/src/vtr_geometry.tpp | 6 + vpr/CMakeLists.txt | 1 + vpr/src/base/vpr_types.h | 32 +- 15 files changed, 612 insertions(+), 361 deletions(-) create mode 100644 libs/librrgraph/CMakeLists.txt rename {vpr/src/device => libs/librrgraph/src}/check_rr_graph_obj.cpp (94%) rename {vpr/src/device => libs/librrgraph/src}/check_rr_graph_obj.h (100%) rename {vpr/src/device => libs/librrgraph/src}/rr_graph_fwd.h (100%) rename {vpr/src/device => libs/librrgraph/src}/rr_graph_obj.cpp (65%) rename {vpr/src/device => libs/librrgraph/src}/rr_graph_obj.h (85%) rename {vpr/src/device => libs/librrgraph/src}/rr_graph_obj_utils.h (87%) create mode 100644 libs/librrgraph/src/rr_graph_types.h rename {vpr/src/device => libs/librrgraph/src}/rr_graph_util.cpp (100%) rename {vpr/src/device => libs/librrgraph/src}/rr_graph_util.h (100%) create mode 100644 libs/librrgraph/test/test_rr_graph.cpp diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 8d09c541d..a85d179f8 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory(EXTERNAL) # Only add warn flags for VPR internal libraries. #add_compile_options(${WARN_FLAGS}) add_subdirectory(libarchfpga) +add_subdirectory(librrgraph) add_subdirectory(libvtrutil) add_subdirectory(liblog) add_subdirectory(libpugiutil) diff --git a/libs/librrgraph/CMakeLists.txt b/libs/librrgraph/CMakeLists.txt new file mode 100644 index 000000000..52f46a170 --- /dev/null +++ b/libs/librrgraph/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.9) + +project("librrgraph") + +file(GLOB_RECURSE EXEC_SOURCE test/test_rr_graph.cpp) +file(GLOB_RECURSE LIB_SOURCES src/*.cpp) +file(GLOB_RECURSE LIB_HEADERS src/*.h) +files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS) + +#Remove test executable from library +list(REMOVE_ITEM LIB_SOURCES ${EXEC_SOURCE}) + +#Create the library +add_library(librrgraph STATIC + ${LIB_HEADERS} + ${LIB_SOURCES}) +target_include_directories(librrgraph PUBLIC ${LIB_INCLUDE_DIRS}) +set_target_properties(librrgraph PROPERTIES PREFIX "") #Avoid extra 'lib' prefix + +#Specify link-time dependancies +target_link_libraries(librrgraph + libarchfpga + libvtrutil) + +#Create the test executable +add_executable(test_rr_graph ${EXEC_SOURCE}) +target_link_libraries(test_rr_graph librrgraph) + +#Supress IPO link warnings if IPO is enabled +#get_target_property(READ_ARCH_USES_IPO read_arch_openfpga INTERPROCEDURAL_OPTIMIZATION) +#if (READ_ARCH_USES_IPO) +# set_target_properties(read_arch_openfpga PROPERTIES LINK_FLAGS ${IPO_LINK_WARN_SUPRESS_FLAGS}) +#endif() + +#install(TARGETS libarchopenfpga read_arch_openfpga DESTINATION bin) diff --git a/vpr/src/device/check_rr_graph_obj.cpp b/libs/librrgraph/src/check_rr_graph_obj.cpp similarity index 94% rename from vpr/src/device/check_rr_graph_obj.cpp rename to libs/librrgraph/src/check_rr_graph_obj.cpp index 253092fb7..69c772fcb 100644 --- a/vpr/src/device/check_rr_graph_obj.cpp +++ b/libs/librrgraph/src/check_rr_graph_obj.cpp @@ -107,7 +107,7 @@ static bool check_rr_graph_source_nodes(const RRGraph& rr_graph) { } } - return invalid_sources; + return !invalid_sources; } /*********************************************************************** @@ -136,7 +136,7 @@ static bool check_rr_graph_sink_nodes(const RRGraph& rr_graph) { } } - return invalid_sinks; + return !invalid_sinks; } /*********************************************************************** @@ -153,48 +153,43 @@ static bool check_rr_graph_sink_nodes(const RRGraph& rr_graph) { * will work properly. **********************************************************************/ bool check_rr_graph(const RRGraph& rr_graph) { - bool check_flag = true; size_t num_err = 0; if (false == check_rr_graph_duplicated_edges(rr_graph)) { VTR_LOG_WARN("Fail in checking duplicated edges !\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_dangling_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking dangling nodes !\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_source_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking source nodes!\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_sink_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking sink nodes!\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_source_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking source nodes!\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_sink_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking sink nodes!\n"); - check_flag = false; num_err++; } /* Error out if there is any fatal errors found */ - VTR_LOG_WARN("Checked Routing Resource graph with %d errors !\n", - num_err); + if (0 < num_err) { + VTR_LOG_WARN("Checked Routing Resource graph with %d errors !\n", + num_err); + } - return check_flag; + return (0 == num_err); } diff --git a/vpr/src/device/check_rr_graph_obj.h b/libs/librrgraph/src/check_rr_graph_obj.h similarity index 100% rename from vpr/src/device/check_rr_graph_obj.h rename to libs/librrgraph/src/check_rr_graph_obj.h diff --git a/vpr/src/device/rr_graph_fwd.h b/libs/librrgraph/src/rr_graph_fwd.h similarity index 100% rename from vpr/src/device/rr_graph_fwd.h rename to libs/librrgraph/src/rr_graph_fwd.h diff --git a/vpr/src/device/rr_graph_obj.cpp b/libs/librrgraph/src/rr_graph_obj.cpp similarity index 65% rename from vpr/src/device/rr_graph_obj.cpp rename to libs/librrgraph/src/rr_graph_obj.cpp index 0cd9c49e8..2df4a77bf 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/libs/librrgraph/src/rr_graph_obj.cpp @@ -7,6 +7,7 @@ #include #include +#include "vtr_geometry.h" #include "vtr_vector_map.h" #include "vtr_log.h" #include "vtr_util.h" @@ -14,13 +15,26 @@ #include "rr_graph_obj.h" #include "rr_graph_obj_utils.h" -//Accessors -RRGraph::node_range RRGraph::nodes() const { - return vtr::make_range(node_ids_.begin(), node_ids_.end()); +/******************************************************************** + * Constructors + *******************************************************************/ +RRGraph::RRGraph() + : num_nodes_(0) + , num_edges_(0) { + //Pass } -RRGraph::edge_range RRGraph::edges() const { - return vtr::make_range(edge_ids_.begin(), edge_ids_.end()); +/******************************************************************** + * Accessors + *******************************************************************/ +RRGraph::lazy_node_range RRGraph::nodes() const { + return vtr::make_range(lazy_node_iterator(RRNodeId(0), invalid_node_ids_), + lazy_node_iterator(RRNodeId(num_nodes_), invalid_node_ids_)); +} + +RRGraph::lazy_edge_range RRGraph::edges() const { + return vtr::make_range(lazy_edge_iterator(RREdgeId(0), invalid_edge_ids_), + lazy_edge_iterator(RREdgeId(num_edges_), invalid_edge_ids_)); } RRGraph::switch_range RRGraph::switches() const { @@ -117,11 +131,11 @@ vtr::Point RRGraph::node_end_coordinate(const RRNodeId& node) const { } short RRGraph::node_fan_in(const RRNodeId& node) const { - return node_in_edges(node).size(); + return node_num_in_edges_[node]; } short RRGraph::node_fan_out(const RRNodeId& node) const { - return node_out_edges(node).size(); + return node_num_out_edges_[node]; } short RRGraph::node_capacity(const RRNodeId& node) const { @@ -189,118 +203,65 @@ RRSegmentId RRGraph::node_segment(const RRNodeId& node) const { return node_segments_[node]; } -/* - * Get the number of configurable input edges of a node - * TODO: we would use the node_num_configurable_in_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough - */ -short RRGraph::node_num_configurable_in_edges(const RRNodeId& node) const { - return node_configurable_in_edges(node).size(); +RRGraph::edge_range RRGraph::node_edges(const RRNodeId& node) const { + VTR_ASSERT_SAFE(valid_node_id(node)); + + return vtr::make_range(node_edges_[node].get(), + node_edges_[node].get() + node_num_in_edges_[node] + node_num_out_edges_[node]); } -/* - * Get the number of configurable output edges of a node - * TODO: we would use the node_num_configurable_out_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough - */ -short RRGraph::node_num_configurable_out_edges(const RRNodeId& node) const { - return node_configurable_out_edges(node).size(); +RRGraph::edge_range RRGraph::node_in_edges(const RRNodeId& node) const { + VTR_ASSERT_SAFE(valid_node_id(node)); + + return vtr::make_range(node_edges_[node].get(), + node_edges_[node].get() + node_num_in_edges_[node]); } -/* - * Get the number of non-configurable input edges of a node - * TODO: we would use the node_num_configurable_in_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough - */ -short RRGraph::node_num_non_configurable_in_edges(const RRNodeId& node) const { - return node_non_configurable_in_edges(node).size(); -} +RRGraph::edge_range RRGraph::node_out_edges(const RRNodeId& node) const { + VTR_ASSERT_SAFE(valid_node_id(node)); -/* - * Get the number of non-configurable output edges of a node - * TODO: we would use the node_num_configurable_out_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough - */ -short RRGraph::node_num_non_configurable_out_edges(const RRNodeId& node) const { - return node_non_configurable_out_edges(node).size(); + return vtr::make_range((node_edges_[node].get() + node_num_in_edges_[node]), + (node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node]); } /* Get the list of configurable edges from the input edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_configurable_in_edges(const RRNodeId& node) const { - /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_in_edges(node).begin(); - - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_in_edges(node).end() - node_num_non_configurable_in_edges_[node]; - - return vtr::make_range(begin, end); + return vtr::make_range(node_edges_[node].get(), + node_edges_[node].get() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]); } -/* Get the list of configurable edges from the input edges of a given node +/* Get the list of non configurable edges from the input edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_non_configurable_in_edges(const RRNodeId& node) const { - /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_in_edges(node).end() - node_num_non_configurable_in_edges_[node]; - - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_in_edges(node).end(); - - return vtr::make_range(begin, end); + return vtr::make_range(node_edges_[node].get() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node], + node_edges_[node].get() + node_num_in_edges_[node]); } -/* Get the list of configurable edges from the input edges of a given node +/* Get the list of configurable edges from the output edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_configurable_out_edges(const RRNodeId& node) const { - /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_out_edges(node).begin(); - - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_out_edges(node).end() - node_num_non_configurable_out_edges_[node]; - - return vtr::make_range(begin, end); + return vtr::make_range((node_edges_[node].get() + node_num_in_edges_[node]), + (node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node] - node_num_non_configurable_out_edges_[node]); } -/* Get the list of configurable edges from the input edges of a given node +/* Get the list of non configurable edges from the output edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_non_configurable_out_edges(const RRNodeId& node) const { - /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_out_edges(node).end() - node_num_non_configurable_out_edges_[node]; - - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_out_edges(node).end(); - - return vtr::make_range(begin, end); -} - -RRGraph::edge_range RRGraph::node_out_edges(const RRNodeId& node) const { - VTR_ASSERT_SAFE(valid_node_id(node)); - return vtr::make_range(node_out_edges_[node].begin(), node_out_edges_[node].end()); -} - -RRGraph::edge_range RRGraph::node_in_edges(const RRNodeId& node) const { - VTR_ASSERT_SAFE(valid_node_id(node)); - return vtr::make_range(node_in_edges_[node].begin(), node_in_edges_[node].end()); + return vtr::make_range((node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node] - node_num_non_configurable_out_edges_[node], + (node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node]); } //Edge attributes @@ -391,22 +352,22 @@ RRNodeId RRGraph::find_node(const short& x, const short& y, const t_rr_type& typ size_t iside = side; /* Check if x, y, type and ptc, side is valid */ - if ((x < 0) /* See if x is smaller than the index of first element */ - || (size_t(x) > node_lookup_.size() - 1)) { /* See if x is large than the index of last element */ + if ((x < 0) /* See if x is smaller than the index of first element */ + || (size_t(x) > node_lookup_.dim_size(0) - 1)) { /* See if x is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } /* Check if x, y, type and ptc, side is valid */ - if ((y < 0) /* See if y is smaller than the index of first element */ - || (size_t(y) > node_lookup_[x].size() - 1)) { /* See if y is large than the index of last element */ + if ((y < 0) /* See if y is smaller than the index of first element */ + || (size_t(y) > node_lookup_.dim_size(1) - 1)) { /* See if y is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } /* Check if x, y, type and ptc, side is valid */ /* itype is always larger than -1, we can skip checking */ - if (itype > node_lookup_[x][y].size() - 1) { /* See if type is large than the index of last element */ + if (itype > node_lookup_.dim_size(2) - 1) { /* See if type is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } @@ -436,21 +397,21 @@ short RRGraph::chan_num_tracks(const short& x, const short& y, const t_rr_type& initialize_fast_node_lookup(); /* Check if x, y, type and ptc is valid */ - if ((x < 0) /* See if x is smaller than the index of first element */ - || (size_t(x) > node_lookup_.size() - 1)) { /* See if x is large than the index of last element */ + if ((x < 0) /* See if x is smaller than the index of first element */ + || (size_t(x) > node_lookup_.dim_size(0) - 1)) { /* See if x is large than the index of last element */ /* Return a zero range! */ return 0; } /* Check if x, y, type and ptc is valid */ - if ((y < 0) /* See if y is smaller than the index of first element */ - || (size_t(y) > node_lookup_[x].size() - 1)) { /* See if y is large than the index of last element */ + if ((y < 0) /* See if y is smaller than the index of first element */ + || (size_t(y) > node_lookup_.dim_size(1) - 1)) { /* See if y is large than the index of last element */ /* Return a zero range! */ return 0; } /* Check if x, y, type and ptc is valid */ - if ((size_t(type) > node_lookup_[x][y].size() - 1)) { /* See if type is large than the index of last element */ + if ((size_t(type) > node_lookup_.dim_size(2) - 1)) { /* See if type is large than the index of last element */ /* Return a zero range! */ return 0; } @@ -488,15 +449,20 @@ bool RRGraph::validate_node_segment(const RRNodeId& node) const { /* Check if the segment id of every node is in range */ bool RRGraph::validate_node_segments() const { bool all_valid = true; - for (auto node : nodes()) { - if (true == validate_node_segment(node)) { + for (size_t id = 0; id < num_nodes_; ++id) { + /* Try to find if this is an invalid id or not */ + if (!valid_node_id(RRNodeId(id))) { + /* Skip this id */ + continue; + } + if (true == validate_node_segment(RRNodeId(id))) { continue; } /* Reach here it means we find an invalid segment id */ all_valid = false; /* Print a warning! */ VTR_LOG_WARN("Node %d has an invalid segment id (%d)!\n", - size_t(node), size_t(node_segment(node))); + id, size_t(node_segment(RRNodeId(id)))); } return all_valid; } @@ -510,15 +476,20 @@ bool RRGraph::validate_edge_switch(const RREdgeId& edge) const { /* Check if the switch id of every edge is in range */ bool RRGraph::validate_edge_switches() const { bool all_valid = true; - for (auto edge : edges()) { - if (true == validate_edge_switch(edge)) { + for (size_t id = 0; id < num_edges_; ++id) { + /* Try to find if this is an invalid id or not */ + if (!valid_edge_id(RREdgeId(id))) { + /* Skip this id */ + continue; + } + if (true == validate_edge_switch(RREdgeId(id))) { continue; } /* Reach here it means we find an invalid segment id */ all_valid = false; /* Print a warning! */ VTR_LOG_WARN("Edge %d has an invalid switch id (%d)!\n", - size_t(edge), size_t(edge_switch(edge))); + id, size_t(edge_switch(RREdgeId(id)))); } return all_valid; } @@ -622,8 +593,13 @@ bool RRGraph::validate_node_edges(const RRNodeId& node) const { /* check if all the nodes' input edges are valid */ bool RRGraph::validate_nodes_in_edges() const { bool all_valid = true; - for (auto node : nodes()) { - if (true == validate_node_in_edges(node)) { + for (size_t id = 0; id < num_nodes_; ++id) { + /* Try to find if this is an invalid id or not */ + if (!valid_node_id(RRNodeId(id))) { + /* Skip this id */ + continue; + } + if (true == validate_node_in_edges(RRNodeId(id))) { continue; } /* Reach here, it means there is something wrong! @@ -637,8 +613,13 @@ bool RRGraph::validate_nodes_in_edges() const { /* check if all the nodes' output edges are valid */ bool RRGraph::validate_nodes_out_edges() const { bool all_valid = true; - for (auto node : nodes()) { - if (true == validate_node_out_edges(node)) { + for (size_t id = 0; id < num_nodes_; ++id) { + /* Try to find if this is an invalid id or not */ + if (!valid_node_id(RRNodeId(id))) { + /* Skip this id */ + continue; + } + if (true == validate_node_out_edges(RRNodeId(id))) { continue; } /* Reach here, it means there is something wrong! @@ -676,15 +657,20 @@ bool RRGraph::validate_edge_sink_node(const RREdgeId& edge) const { /* Check if source nodes of a edge are all valid */ bool RRGraph::validate_edge_src_nodes() const { bool all_valid = true; - for (auto edge : edges()) { - if (true == validate_edge_src_node(edge)) { + for (size_t id = 0; id < num_edges_; ++id) { + /* Try to find if this is an invalid id or not */ + if (!valid_edge_id(RREdgeId(id))) { + /* Skip this id */ + continue; + } + if (true == validate_edge_src_node(RREdgeId(id))) { continue; } /* Reach here, it means there is something wrong! * Print a warning */ VTR_LOG_WARN("Edge %d has a invalid source node %d!\n", - size_t(edge), size_t(edge_src_node(edge))); + id, size_t(edge_src_node(RREdgeId(id)))); all_valid = false; } return all_valid; @@ -693,15 +679,20 @@ bool RRGraph::validate_edge_src_nodes() const { /* Check if source nodes of a edge are all valid */ bool RRGraph::validate_edge_sink_nodes() const { bool all_valid = true; - for (auto edge : edges()) { - if (true == validate_edge_sink_node(edge)) { + for (size_t id = 0; id < num_edges_; ++id) { + /* Try to find if this is an invalid id or not */ + if (!valid_edge_id(RREdgeId(id))) { + /* Skip this id */ + continue; + } + if (true == validate_edge_sink_node(RREdgeId(id))) { continue; } /* Reach here, it means there is something wrong! * Print a warning */ VTR_LOG_WARN("Edge %d has a invalid sink node %d!\n", - size_t(edge), size_t(edge_sink_node(edge))); + id, size_t(edge_sink_node(RREdgeId(id)))); all_valid = false; } return all_valid; @@ -714,7 +705,6 @@ bool RRGraph::validate_edge_sink_nodes() const { * Warnings are thrown if optional checking fails */ bool RRGraph::validate() const { - bool check_flag = true; size_t num_err = 0; initialize_fast_node_lookup(); @@ -724,34 +714,32 @@ bool RRGraph::validate() const { */ if (false == validate_sizes()) { VTR_LOG_WARN("Fail in validating node- and edge-related vector sizes!\n"); - check_flag = false; num_err++; } /* Fundamental check */ if (false == validate_nodes_edges()) { VTR_LOG_WARN("Fail in validating edges connected to each node!\n"); - check_flag = false; num_err++; } if (false == validate_node_segments()) { VTR_LOG_WARN("Fail in validating segment IDs of nodes !\n"); - check_flag = false; num_err++; } if (false == validate_edge_switches()) { VTR_LOG_WARN("Fail in validating switch IDs of edges !\n"); - check_flag = false; num_err++; } /* Error out if there is any fatal errors found */ - VTR_LOG_ERROR("Routing Resource graph is not valid due to %d fatal errors !\n", - num_err); + if (0 < num_err) { + VTR_LOG_ERROR("Routing Resource graph is not valid due to %d fatal errors !\n", + num_err); + } - return check_flag; + return (0 == num_err); } bool RRGraph::is_dirty() const { @@ -767,55 +755,58 @@ void RRGraph::clear_dirty() { } /* Reserve a list of nodes */ -void RRGraph::reserve_nodes(const int& num_nodes) { +void RRGraph::reserve_nodes(const unsigned long& num_nodes) { /* Reserve the full set of vectors related to nodes */ /* Basic information */ - this->node_ids_.reserve(num_nodes); this->node_types_.reserve(num_nodes); + this->node_bounding_boxes_.reserve(num_nodes); + this->node_capacities_.reserve(num_nodes); this->node_ptc_nums_.reserve(num_nodes); + this->node_cost_indices_.reserve(num_nodes); this->node_directions_.reserve(num_nodes); this->node_sides_.reserve(num_nodes); this->node_Rs_.reserve(num_nodes); this->node_Cs_.reserve(num_nodes); this->node_segments_.reserve(num_nodes); + + /* Edge-related vectors */ + this->node_num_in_edges_.reserve(num_nodes); + this->node_num_out_edges_.reserve(num_nodes); this->node_num_non_configurable_in_edges_.reserve(num_nodes); this->node_num_non_configurable_out_edges_.reserve(num_nodes); - - /* Edge-relate vectors */ - this->node_in_edges_.reserve(num_nodes); - this->node_out_edges_.reserve(num_nodes); + this->node_edges_.reserve(num_nodes); } /* Reserve a list of edges */ -void RRGraph::reserve_edges(const int& num_edges) { +void RRGraph::reserve_edges(const unsigned long& num_edges) { /* Reserve the full set of vectors related to edges */ - this->edge_ids_.reserve(num_edges); this->edge_src_nodes_.reserve(num_edges); this->edge_sink_nodes_.reserve(num_edges); this->edge_switches_.reserve(num_edges); } /* Reserve a list of switches */ -void RRGraph::reserve_switches(const int& num_switches) { +void RRGraph::reserve_switches(const size_t& num_switches) { this->switch_ids_.reserve(num_switches); this->switches_.reserve(num_switches); } /* Reserve a list of segments */ -void RRGraph::reserve_segments(const int& num_segments) { +void RRGraph::reserve_segments(const size_t& num_segments) { this->segment_ids_.reserve(num_segments); this->segments_.reserve(num_segments); } /* Mutators */ RRNodeId RRGraph::create_node(const t_rr_type& type) { - //Allocate an ID - RRNodeId node_id = RRNodeId(node_ids_.size()); + /* Allocate an ID */ + RRNodeId node_id = RRNodeId(num_nodes_); + /* Expand range of node ids */ + num_nodes_++; - //Initialize the attributes - node_ids_.push_back(node_id); + /* Initialize the attributes */ node_types_.push_back(type); node_bounding_boxes_.emplace_back(-1, -1, -1, -1); @@ -827,12 +818,14 @@ RRNodeId RRGraph::create_node(const t_rr_type& type) { node_sides_.push_back(NUM_SIDES); node_Rs_.push_back(0.); node_Cs_.push_back(0.); + node_segments_.push_back(RRSegmentId::INVALID()); - node_in_edges_.emplace_back(); //Initially empty - node_out_edges_.emplace_back(); //Initially empty + node_edges_.emplace_back(); //Initially empty - node_num_non_configurable_in_edges_.emplace_back(); //Initially empty - node_num_non_configurable_out_edges_.emplace_back(); //Initially empty + node_num_in_edges_.emplace_back(0); + node_num_out_edges_.emplace_back(0); + node_num_non_configurable_in_edges_.emplace_back(0); + node_num_non_configurable_out_edges_.emplace_back(0); invalidate_fast_node_lookup(); @@ -846,19 +839,20 @@ RREdgeId RRGraph::create_edge(const RRNodeId& source, const RRNodeId& sink, cons VTR_ASSERT(valid_node_id(sink)); VTR_ASSERT(valid_switch_id(switch_id)); - //Allocate an ID - RREdgeId edge_id = RREdgeId(edge_ids_.size()); - - //Initialize the attributes - edge_ids_.push_back(edge_id); + /* Allocate an ID */ + RREdgeId edge_id = RREdgeId(num_edges_); + /* Expand range of edge ids */ + num_edges_++; + /* Initialize the attributes */ edge_src_nodes_.push_back(source); edge_sink_nodes_.push_back(sink); edge_switches_.push_back(switch_id); - //Add the edge to the nodes - node_out_edges_[source].push_back(edge_id); - node_in_edges_[sink].push_back(edge_id); + //We do not create the entry in node_edges_ here! + //For memory efficiency this is done when + //rebuild_node_edges() is called (i.e. after all + //edges have been created). VTR_ASSERT(validate_sizes()); @@ -902,7 +896,7 @@ void RRGraph::remove_node(const RRNodeId& node) { } //Mark node invalid - node_ids_[node] = RRNodeId::INVALID(); + invalid_node_ids_.insert(node); //Invalidate the node look-up invalidate_fast_node_lookup(); @@ -918,23 +912,24 @@ void RRGraph::remove_edge(const RREdgeId& edge) { RRNodeId src_node = edge_src_node(edge); RRNodeId sink_node = edge_sink_node(edge); - //Invalidate node to edge references - // TODO: consider making this optional (e.g. if called from remove_node) - for (size_t i = 0; i < node_out_edges_[src_node].size(); ++i) { - if (node_out_edges_[src_node][i] == edge) { - node_out_edges_[src_node][i] = RREdgeId::INVALID(); + /* Invalidate node to edge references + * TODO: consider making this optional (e.g. if called from remove_node) + */ + for (size_t i = 0; i < node_num_in_edges_[src_node]; ++i) { + if (node_edges_[src_node][i] == edge) { + node_edges_[src_node][i] = RREdgeId::INVALID(); break; } } - for (size_t i = 0; i < node_in_edges_[sink_node].size(); ++i) { - if (node_in_edges_[sink_node][i] == edge) { - node_in_edges_[sink_node][i] = RREdgeId::INVALID(); + for (size_t i = node_num_in_edges_[sink_node]; i < node_num_in_edges_[sink_node] + node_num_out_edges_[sink_node]; ++i) { + if (node_edges_[sink_node][i] == edge) { + node_edges_[sink_node][i] = RREdgeId::INVALID(); break; } } - //Mark edge invalid - edge_ids_[edge] = RREdgeId::INVALID(); + /* Mark edge invalid */ + invalid_edge_ids_.insert(edge); set_dirty(); } @@ -1047,94 +1042,150 @@ void RRGraph::set_node_segment(const RRNodeId& node, const RRSegmentId& segment_ node_segments_[node] = segment_id; } +void RRGraph::rebuild_node_edges() { + node_edges_.resize(nodes().size()); + node_num_in_edges_.resize(nodes().size(), 0); + node_num_out_edges_.resize(nodes().size(), 0); + node_num_non_configurable_in_edges_.resize(nodes().size(), 0); + node_num_non_configurable_out_edges_.resize(nodes().size(), 0); -/* For a given node in a rr_graph - * classify the edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_node_in_edges(const RRNodeId& node) { - //Partition the edges so the first set of edges are all configurable, and the later are not - auto first_non_config_edge = std::partition(node_in_edges_[node].begin(), node_in_edges_[node].end(), - [&](const RREdgeId edge) { return edge_is_configurable(edge); }); /* Condition to partition edges */ + //Count the number of edges of each type + for (RREdgeId edge : edges()) { + if (!edge) continue; - size_t num_conf_edges = std::distance(node_in_edges_[node].begin(), first_non_config_edge); - size_t num_non_conf_edges = node_in_edges_[node].size() - num_conf_edges; //Note we calculate using the size_t to get full range + RRNodeId src_node = edge_src_node(edge); + RRNodeId sink_node = edge_sink_node(edge); + bool config = edge_is_configurable(edge); - /* Check that within allowable range (no overflow when stored as num_non_configurable_edges_ - */ - VTR_ASSERT_MSG(num_non_conf_edges <= node_in_edges_[node].size(), - "Exceeded RR node maximum number of non-configurable input edges"); - - node_num_non_configurable_in_edges_[node] = num_non_conf_edges; //Narrowing -} - -/* For a given node in a rr_graph - * classify the edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_node_out_edges(const RRNodeId& node) { - //Partition the edges so the first set of edges are all configurable, and the later are not - auto first_non_config_edge = std::partition(node_out_edges_[node].begin(), node_out_edges_[node].end(), - [&](const RREdgeId edge) { return edge_is_configurable(edge); }); /* Condition to partition edges */ - - size_t num_conf_edges = std::distance(node_out_edges_[node].begin(), first_non_config_edge); - size_t num_non_conf_edges = node_out_edges_[node].size() - num_conf_edges; //Note we calculate using the size_t to get full range - - /* Check that within allowable range (no overflow when stored as num_non_configurable_edges_ - */ - VTR_ASSERT_MSG(num_non_conf_edges <= node_out_edges_[node].size(), - "Exceeded RR node maximum number of non-configurable output edges"); - - node_num_non_configurable_out_edges_[node] = num_non_conf_edges; //Narrowing -} - -/* For all nodes in a rr_graph - * classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_in_edges() { - /* For each node */ - for (auto node : nodes()) { - this->partition_node_in_edges(node); + ++node_num_out_edges_[src_node]; + ++node_num_in_edges_[sink_node]; + if (!config) { + ++node_num_non_configurable_out_edges_[src_node]; + ++node_num_non_configurable_in_edges_[sink_node]; + } } -} -/* For all nodes in a rr_graph - * classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_out_edges() { - /* For each node */ - for (auto node : nodes()) { - this->partition_node_out_edges(node); + //Allocate precisely the correct space for each nodes edge list + for (RRNodeId node : nodes()) { + if (!node) continue; + + node_edges_[node] = std::make_unique(node_num_in_edges_[node] + node_num_out_edges_[node]); } -} -/* For all nodes in a rr_graph - * classify both input and output edges of each node - * to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_edges() { - /* Partition input edges */ - this->partition_in_edges(); - /* Partition output edges */ - this->partition_out_edges(); + //Insert the edges into the node lists + { + vtr::vector inserted_edge_cnt(nodes().size(), 0); + for (RREdgeId edge : edges()) { + RRNodeId src_node = edge_src_node(edge); + RRNodeId sink_node = edge_sink_node(edge); + + node_edges_[src_node][inserted_edge_cnt[src_node]++] = edge; + node_edges_[sink_node][inserted_edge_cnt[sink_node]++] = edge; + } + } + +#if 0 + //TODO: Sanity Check remove! + for (RRNodeId node : nodes()) { + for (size_t iedge = 0; iedge < node_num_in_edges_[node] + node_num_out_edges_[node]; ++iedge) { + RREdgeId edge = node_edges_[node][iedge]; + VTR_ASSERT(edge_src_node(edge) == node || edge_sink_node(edge) == node); + } + } +#endif + + //Partition each node's edge lists according to their type to line up with the counts + + auto is_configurable_edge = [&](const RREdgeId edge) { + return edge_is_configurable(edge); + }; + + for (RRNodeId node : nodes()) { + if (!node) continue; + + //We partition the nodes first by incoming/outgoing: + // + // +---------------------------+-----------------------------+ + // | in | out | + // +---------------------------+-----------------------------+ + // + //and then the two subsets by configurability. So the final ordering is: + // + // +-----------+---------------+------------+----------------+ + // | in_config | in_non_config | out_config | out_non_config | + // +-----------+---------------+------------+----------------+ + // + + //Partition first into incoming/outgoing + auto is_incoming_edge = [&](const RREdgeId edge) { + return edge_sink_node(edge) == node; + }; + std::partition(node_edges_[node].get(), + node_edges_[node].get() + node_num_in_edges_[node] + node_num_out_edges_[node], + is_incoming_edge); + + //Partition incoming by configurable/non-configurable + std::partition(node_edges_[node].get(), + node_edges_[node].get() + node_num_in_edges_[node], + is_configurable_edge); + + //Partition outgoing by configurable/non-configurable + std::partition(node_edges_[node].get() + node_num_in_edges_[node], + node_edges_[node].get() + node_num_in_edges_[node] + node_num_out_edges_[node], + is_configurable_edge); + +#if 0 + //TODO: Sanity check remove! + size_t nedges = node_num_in_edges_[node] + node_num_out_edges_[node]; + for (size_t iedge = 0; iedge < nedges; ++iedge) { + RREdgeId edge = node_edges_[node][iedge]; + if (iedge < node_num_in_edges_[node]) { //Incoming + VTR_ASSERT(edge_sink_node(edge) == node); + if (iedge < node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]) { + VTR_ASSERT(edge_is_configurable(edge)); + } else { + VTR_ASSERT(!edge_is_configurable(edge)); + } + } else { //Outgoing + VTR_ASSERT(edge_src_node(edge) == node); + if (iedge < node_num_in_edges_[node] + node_num_out_edges_[node] - node_num_non_configurable_out_edges_[node]) { + VTR_ASSERT(edge_is_configurable(edge)); + } else { + VTR_ASSERT(!edge_is_configurable(edge)); + } + } + } +#endif + } } void RRGraph::build_fast_node_lookup() const { + /* Free the current fast node look-up, we will rebuild a new one here */ invalidate_fast_node_lookup(); - for (auto node : nodes()) { + /* Get the max (x,y) and then we can resize the ndmatrix */ + vtr::Point max_coord(0, 0); + for (size_t id = 0; id < num_nodes_; ++id) { + /* Try to find if this is an invalid id or not */ + if (!valid_node_id(RRNodeId(id))) { + /* Skip this id */ + continue; + } + max_coord.set_x(std::max(max_coord.x(), node_xlow(RRNodeId(id)))); + max_coord.set_y(std::max(max_coord.y(), node_ylow(RRNodeId(id)))); + } + node_lookup_.resize({(size_t)max_coord.x() + 1, (size_t)max_coord.y() + 1, NUM_RR_TYPES + 1}); + + for (size_t id = 0; id < num_nodes_; ++id) { + /* Try to find if this is an invalid id or not */ + if (!valid_node_id(RRNodeId(id))) { + /* Skip this id */ + continue; + } + RRNodeId node = RRNodeId(id); size_t x = node_xlow(node); - if (x >= node_lookup_.size()) { - node_lookup_.resize(x + 1); - } - size_t y = node_ylow(node); - if (y >= node_lookup_[x].size()) { - node_lookup_[x].resize(y + 1); - } - size_t itype = node_type(node); - if (itype >= node_lookup_[x][y].size()) { - node_lookup_[x][y].resize(itype + 1); - } size_t ptc = node_ptc_num(node); if (ptc >= node_lookup_[x][y][itype].size()) { @@ -1172,11 +1223,13 @@ void RRGraph::initialize_fast_node_lookup() const { } bool RRGraph::valid_node_id(const RRNodeId& node) const { - return size_t(node) < node_ids_.size() && node_ids_[node] == node; + return (size_t(node) < num_nodes_) + && (!invalid_node_ids_.count(node)); } bool RRGraph::valid_edge_id(const RREdgeId& edge) const { - return size_t(edge) < edge_ids_.size() && edge_ids_[edge] == edge; + return (size_t(edge) < num_edges_) + && (!invalid_edge_ids_.count(edge)); } /* check if a given switch id is valid or not */ @@ -1205,26 +1258,25 @@ bool RRGraph::validate_sizes() const { } bool RRGraph::validate_node_sizes() const { - return node_types_.size() == node_ids_.size() - && node_bounding_boxes_.size() == node_ids_.size() - && node_capacities_.size() == node_ids_.size() - && node_ptc_nums_.size() == node_ids_.size() - && node_cost_indices_.size() == node_ids_.size() - && node_directions_.size() == node_ids_.size() - && node_sides_.size() == node_ids_.size() - && node_Rs_.size() == node_ids_.size() - && node_Cs_.size() == node_ids_.size() - && node_segments_.size() == node_ids_.size() - && node_num_non_configurable_in_edges_.size() == node_ids_.size() - && node_num_non_configurable_out_edges_.size() == node_ids_.size() - && node_in_edges_.size() == node_ids_.size() - && node_out_edges_.size() == node_ids_.size(); + return node_types_.size() == num_nodes_ + && node_bounding_boxes_.size() == num_nodes_ + && node_capacities_.size() == num_nodes_ + && node_ptc_nums_.size() == num_nodes_ + && node_cost_indices_.size() == num_nodes_ + && node_directions_.size() == num_nodes_ + && node_sides_.size() == num_nodes_ + && node_Rs_.size() == num_nodes_ + && node_Cs_.size() == num_nodes_ + && node_segments_.size() == num_nodes_ + && node_num_non_configurable_in_edges_.size() == num_nodes_ + && node_num_non_configurable_out_edges_.size() == num_nodes_ + && node_edges_.size() == num_nodes_; } bool RRGraph::validate_edge_sizes() const { - return edge_src_nodes_.size() == edge_ids_.size() - && edge_sink_nodes_.size() == edge_ids_.size() - && edge_switches_.size() == edge_ids_.size(); + return edge_src_nodes_.size() == num_edges_ + && edge_sink_nodes_.size() == num_edges_ + && edge_switches_.size() == num_edges_; } bool RRGraph::validate_switch_sizes() const { @@ -1236,8 +1288,8 @@ bool RRGraph::validate_segment_sizes() const { } void RRGraph::compress() { - vtr::vector node_id_map(node_ids_.size()); - vtr::vector edge_id_map(edge_ids_.size()); + vtr::vector node_id_map(num_nodes_); + vtr::vector edge_id_map(num_edges_); build_id_maps(node_id_map, edge_id_map); @@ -1248,17 +1300,48 @@ void RRGraph::compress() { invalidate_fast_node_lookup(); + /* Clear invalid node list */ + invalid_node_ids_.clear(); + + /* Clear invalid edge list */ + invalid_edge_ids_.clear(); + clear_dirty(); } void RRGraph::build_id_maps(vtr::vector& node_id_map, vtr::vector& edge_id_map) { - node_id_map = compress_ids(node_ids_); - edge_id_map = compress_ids(edge_ids_); + /* Build node ids including invalid ids and compress */ + vtr::vector node_ids; + for (size_t id = 0; id < num_nodes_; ++id) { + /* Try to find if this is an invalid id or not */ + if (!valid_node_id(RRNodeId(id))) { + /* Give and invalid id */ + node_ids.push_back(RRNodeId::INVALID()); + continue; + } + /* Reach here, this is a valid id, push to the edge list */ + node_ids.push_back(RRNodeId(id)); + } + node_id_map = compress_ids(node_ids); + + /* Build edge ids including invalid ids and compress */ + vtr::vector edge_ids; + for (size_t id = 0; id < num_edges_; ++id) { + /* Try to find if this is an invalid id or not */ + if (!valid_edge_id(RREdgeId(id))) { + /* Give and invalid id */ + edge_ids.push_back(RREdgeId::INVALID()); + continue; + } + /* Reach here, this is a valid id, push to the edge list */ + edge_ids.push_back(RREdgeId(id)); + } + edge_id_map = compress_ids(edge_ids); } void RRGraph::clean_nodes(const vtr::vector& node_id_map) { - node_ids_ = clean_and_reorder_ids(node_id_map); + num_nodes_ = node_id_map.size(); node_types_ = clean_and_reorder_values(node_types_, node_id_map); @@ -1272,39 +1355,46 @@ void RRGraph::clean_nodes(const vtr::vector& node_id_map) { node_Rs_ = clean_and_reorder_values(node_Rs_, node_id_map); node_Cs_ = clean_and_reorder_values(node_Cs_, node_id_map); - VTR_ASSERT(validate_node_sizes()); + node_segments_ = clean_and_reorder_values(node_segments_, node_id_map); + node_num_non_configurable_in_edges_ = clean_and_reorder_values(node_num_non_configurable_in_edges_, node_id_map); + node_num_non_configurable_out_edges_ = clean_and_reorder_values(node_num_non_configurable_out_edges_, node_id_map); + node_num_in_edges_ = clean_and_reorder_values(node_num_in_edges_, node_id_map); + node_num_out_edges_ = clean_and_reorder_values(node_num_out_edges_, node_id_map); + //node_edges_ = clean_and_reorder_values(node_edges_, node_id_map); - VTR_ASSERT_MSG(are_contiguous(node_ids_), "Ids should be contiguous"); - VTR_ASSERT_MSG(all_valid(node_ids_), "All Ids should be valid"); + VTR_ASSERT(validate_node_sizes()); } void RRGraph::clean_edges(const vtr::vector& edge_id_map) { - edge_ids_ = clean_and_reorder_ids(edge_id_map); + num_edges_ = edge_id_map.size(); edge_src_nodes_ = clean_and_reorder_values(edge_src_nodes_, edge_id_map); edge_sink_nodes_ = clean_and_reorder_values(edge_sink_nodes_, edge_id_map); edge_switches_ = clean_and_reorder_values(edge_switches_, edge_id_map); VTR_ASSERT(validate_edge_sizes()); - - VTR_ASSERT_MSG(are_contiguous(edge_ids_), "Ids should be contiguous"); - VTR_ASSERT_MSG(all_valid(edge_ids_), "All Ids should be valid"); } void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_map) { - for (const auto& node : nodes()) { - node_in_edges_[node] = update_valid_refs(node_in_edges_[node], edge_id_map); - node_out_edges_[node] = update_valid_refs(node_out_edges_[node], edge_id_map); + for (size_t id = 0; id < num_nodes_; ++id) { + /* Try to find if this is an invalid id or not */ + if (!valid_node_id(RRNodeId(id))) { + /* Skip this id */ + continue; + } + RRNodeId node = RRNodeId(id); - VTR_ASSERT_MSG(all_valid(node_in_edges_[node]), "All Ids should be valid"); - VTR_ASSERT_MSG(all_valid(node_out_edges_[node]), "All Ids should be valid"); + auto begin = node_edges_[node].get(); + auto end = begin + node_num_in_edges_[node] + node_num_out_edges_[node]; + update_valid_refs(begin, end, edge_id_map); + + VTR_ASSERT_MSG(all_valid(begin, end), "All Ids should be valid"); } } /* Empty all the vectors related to nodes */ void RRGraph::clear_nodes() { - node_ids_.clear(); - + num_nodes_ = 0; node_types_.clear(); node_bounding_boxes_.clear(); @@ -1317,11 +1407,12 @@ void RRGraph::clear_nodes() { node_Cs_.clear(); node_segments_.clear(); + node_num_in_edges_.clear(); + node_num_out_edges_.clear(); node_num_non_configurable_in_edges_.clear(); node_num_non_configurable_out_edges_.clear(); - node_in_edges_.clear(); - node_out_edges_.clear(); + node_edges_.clear(); /* clean node_look_up */ node_lookup_.clear(); @@ -1329,7 +1420,7 @@ void RRGraph::clear_nodes() { /* Empty all the vectors related to edges */ void RRGraph::clear_edges() { - edge_ids_.clear(); + num_edges_ = 0; edge_src_nodes_.clear(); edge_sink_nodes_.clear(); edge_switches_.clear(); diff --git a/vpr/src/device/rr_graph_obj.h b/libs/librrgraph/src/rr_graph_obj.h similarity index 85% rename from vpr/src/device/rr_graph_obj.h rename to libs/librrgraph/src/rr_graph_obj.h index f34b11162..85bf7de4b 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/libs/librrgraph/src/rr_graph_obj.h @@ -198,30 +198,44 @@ /* Standard header files required go first */ #include #include +#include +#include /* EXTERNAL library header files go second*/ +#include "vtr_ndmatrix.h" #include "vtr_vector.h" #include "vtr_range.h" #include "vtr_geometry.h" #include "arch_types.h" /* VPR header files go third */ -#include "vpr_types.h" +#include "rr_graph_types.h" #include "rr_graph_fwd.h" class RRGraph { public: /* Types */ + //Lazy iterator utility forward declaration + template + class lazy_id_iterator; + /* Iterators used to create iterator-based loop for nodes/edges/switches/segments */ typedef vtr::vector::const_iterator node_iterator; typedef vtr::vector::const_iterator edge_iterator; typedef vtr::vector::const_iterator switch_iterator; typedef vtr::vector::const_iterator segment_iterator; + typedef lazy_id_iterator lazy_node_iterator; + typedef lazy_id_iterator lazy_edge_iterator; /* Ranges used to create range-based loop for nodes/edges/switches/segments */ typedef vtr::Range node_range; - typedef vtr::Range edge_range; + typedef vtr::Range edge_range; typedef vtr::Range switch_range; typedef vtr::Range segment_range; + typedef vtr::Range lazy_node_range; + typedef vtr::Range lazy_edge_range; + + public: /* Constructors */ + RRGraph(); public: /* Accessors */ /* Aggregates: create range-based loops for nodes/edges/switches/segments @@ -247,8 +261,8 @@ class RRGraph { * // Do something with each segment * } */ - node_range nodes() const; - edge_range edges() const; + lazy_node_range nodes() const; + lazy_edge_range edges() const; switch_range switches() const; segment_range segments() const; @@ -445,23 +459,9 @@ class RRGraph { */ RRSegmentId node_segment(const RRNodeId& node) const; - /* Get the number of non-configurable incoming edges to a node */ - short node_num_configurable_in_edges(const RRNodeId& node) const; - - /* Get the number of non-configurable outgoing edges from a node */ - short node_num_non_configurable_in_edges(const RRNodeId& node) const; - - /* Get the number of configurable output edges of a node */ - short node_num_configurable_out_edges(const RRNodeId& node) const; - - /* Get the number of non-configurable output edges of a node */ - short node_num_non_configurable_out_edges(const RRNodeId& node) const; - - /* Get the range (list) of edges related to a given node */ - edge_range node_configurable_in_edges(const RRNodeId& node) const; - edge_range node_non_configurable_in_edges(const RRNodeId& node) const; - edge_range node_configurable_out_edges(const RRNodeId& node) const; - edge_range node_non_configurable_out_edges(const RRNodeId& node) const; + //Returns an iterable range of all edges (incoming & outgoing) for + //the specified node + edge_range node_edges(const RRNodeId& node) const; /* Get a list of edge ids, which are incoming edges to a node */ edge_range node_in_edges(const RRNodeId& node) const; @@ -469,6 +469,12 @@ class RRGraph { /* Get a list of edge ids, which are outgoing edges from a node */ edge_range node_out_edges(const RRNodeId& node) const; + /* Get the range (list) of edges related to a given node */ + edge_range node_configurable_in_edges(const RRNodeId& node) const; + edge_range node_non_configurable_in_edges(const RRNodeId& node) const; + edge_range node_configurable_out_edges(const RRNodeId& node) const; + edge_range node_non_configurable_out_edges(const RRNodeId& node) const; + /* Edge-related attributes * An example to explain the terminology used in RRGraph * edgeA @@ -583,10 +589,10 @@ class RRGraph { * rr_graph.create_node(CHANX); * } */ - void reserve_nodes(const int& num_nodes); - void reserve_edges(const int& num_edges); - void reserve_switches(const int& num_switches); - void reserve_segments(const int& num_segments); + void reserve_nodes(const unsigned long& num_nodes); + void reserve_edges(const unsigned long& num_edges); + void reserve_switches(const size_t& num_switches); + void reserve_segments(const size_t& num_segments); /* Add new elements (node, edge, switch, etc.) to RRGraph */ /* Add a node to the RRGraph with a deposited type @@ -596,6 +602,7 @@ class RRGraph { * set_node_xlow(node, 0); */ RRNodeId create_node(const t_rr_type& type); + /* Add a edge to the RRGraph, by providing the source and sink node * This function will automatically create a node and * configure the nodes and edges in connection @@ -690,15 +697,14 @@ class RRGraph { /* Set the routing segment linked to a node, only applicable to CHANX and CHANY */ void set_node_segment(const RRNodeId& node, const RRSegmentId& segment_index); - /* Edge partitioning is performed for efficiency, - * so we can store configurable and non-configurable edge lists for a node in one vector, - * and efficiently iterate over all edges, or only the configurable or non-configurable subsets. - * This function will re-organize the incoming and outgoing edges of each node, - * i.e., node_in_edges() and node_out_edges(): - * 1. configurable edges (1st part of the vectors) - * 2. non-configurable edges (2nd part of the vectors) + /* + * Build the node to edge references to allow iteration through + * a node's in/out edges. + * + * Must be called before any node_*_in_edges() or node_*_out_edges() member + * functions can be called. */ - void partition_edges(); + void rebuild_node_edges(); /* Graph-level Clean-up, remove invalid nodes/edges etc. * This will clear the dirty flag (query by is_dirty()) of RRGraph object, if it was set @@ -708,18 +714,52 @@ class RRGraph { /* top-level function to free, should be called when to delete a RRGraph */ void clear(); - private: /* Internal Mutators to perform edge partitioning */ - /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_node_in_edges(const RRNodeId& node); + public: /* Type implementations */ + /* + * This class (forward delcared above) is a template used to represent a lazily calculated + * iterator of the specified ID type. The key assumption made is that the ID space is + * contiguous and can be walked by incrementing the underlying ID value. To account for + * invalid IDs, it keeps a reference to the invalid ID set and returns ID::INVALID() for + * ID values in the set. + * + * It is used to lazily create an iteration range (e.g. as returned by RRGraph::edges() RRGraph::nodes()) + * just based on the count of allocated elements (i.e. RRGraph::num_nodes_ or RRGraph::num_edges_), + * and the set of any invalid IDs (i.e. RRGraph::invalid_node_ids_, RRGraph::invalid_edge_ids_). + */ + template + class lazy_id_iterator : public std::iterator { + public: + //Since we pass ID as a template to std::iterator we need to use an explicit 'typename' + //to bring the value_type and iterator names into scope + typedef typename std::iterator::value_type value_type; + typedef typename std::iterator::iterator iterator; - /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_node_out_edges(const RRNodeId& node); + lazy_id_iterator(value_type init, const std::unordered_set& invalid_ids) + : value_(init) + , invalid_ids_(invalid_ids) {} - /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_in_edges(); + //Advance to the next ID value + iterator operator++() { + value_ = ID(size_t(value_) + 1); + return *this; + } - /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_out_edges(); + //Advance to the previous ID value + iterator operator--() { + value_ = ID(size_t(value_) - 1); + return *this; + } + + //Dereference the iterator + value_type operator*() const { return (invalid_ids_.count(value_)) ? ID::INVALID() : value_; } + + friend bool operator==(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return lhs.value_ == rhs.value_; } + friend bool operator!=(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return !(lhs == rhs); } + + private: + value_type value_; + const std::unordered_set& invalid_ids_; + }; private: /* Internal free functions */ void clear_nodes(); @@ -787,7 +827,9 @@ class RRGraph { private: /* Internal Data */ /* Node related data */ - vtr::vector node_ids_; /* Unique identifiers for the nodes */ + size_t num_nodes_; /* Range of node ids */ + std::unordered_set invalid_node_ids_; /* Invalid edge ids */ + vtr::vector node_types_; vtr::vector> node_bounding_boxes_; @@ -800,15 +842,44 @@ class RRGraph { vtr::vector node_Rs_; vtr::vector node_Cs_; vtr::vector node_segments_; /* Segment ids for each node */ - /* Record the dividing point between configurable and non-configurable edges for each node */ - vtr::vector node_num_non_configurable_in_edges_; - vtr::vector node_num_non_configurable_out_edges_; - vtr::vector> node_in_edges_; - vtr::vector> node_out_edges_; + /* + * We store the edges assoicated with each node in a single array per node (for memory efficiency). + * + * The array of edges is sorted into sub-ranges to allow for easy iteration (with node_in_edges(), + * node_non_configurable_out_edges() etc.). + * + * For a particular 'node' we store the sizes of the various sub-ranges in the node_num_* members, + * from which the delimiters for each sub-range can be calculated. + * + * + * node_edges_[node]: + * + * + * node_num_non_configurable_in_edges_[node] node_num_non_configurable_out_edges_[node] + * <-------------------> <--------------------> + * + * +------------------+---------------------+------------------+----------------------+ + * | in_edges_config | in_edges_non_config | out_edges_config | out_edges_non_config | + * +------------------+---------------------+------------------+----------------------+ + * + * <--------------------------------------> <---------------------------------------> + * node_num_in_edges_[node] node_num_out_edges_[node] + * + * All elements of node_edges_ should be initialized after all edges have been created (with create_edge()), + * by calling rebuild_node_edges(), which will allocate node_edges_, add the relevant edges and partition + * each node's arrays into the appropriate. rebuild_node_edges() also initializes all the node_num_* members + * based on the edges (created with create_edge()) in the edge_* members. + */ + vtr::vector node_num_in_edges_; + vtr::vector node_num_out_edges_; + vtr::vector node_num_non_configurable_in_edges_; + vtr::vector node_num_non_configurable_out_edges_; + vtr::vector> node_edges_; /* Edge related data */ - vtr::vector edge_ids_; /* unique identifiers for edges */ + size_t num_edges_; /* Range of edge ids */ + std::unordered_set invalid_edge_ids_; /* Invalid edge ids */ vtr::vector edge_src_nodes_; vtr::vector edge_sink_nodes_; vtr::vector edge_switches_; @@ -836,7 +907,7 @@ class RRGraph { /* Fast look-up to search a node by its type, coordinator and ptc_num * Indexing of fast look-up: [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] */ - typedef std::vector>>>> NodeLookup; + typedef vtr::NdMatrix>, 3> NodeLookup; mutable NodeLookup node_lookup_; }; diff --git a/vpr/src/device/rr_graph_obj_utils.h b/libs/librrgraph/src/rr_graph_obj_utils.h similarity index 87% rename from vpr/src/device/rr_graph_obj_utils.h rename to libs/librrgraph/src/rr_graph_obj_utils.h index 910b0ce3a..5c3a8f6d6 100644 --- a/vpr/src/device/rr_graph_obj_utils.h +++ b/libs/librrgraph/src/rr_graph_obj_utils.h @@ -38,6 +38,16 @@ bool all_valid(const Container& values) { return true; } +template +bool all_valid(Iterator begin, Iterator end) { + for (auto itr = begin; itr != end; ++itr) { + if (!*itr) { + return false; + } + } + return true; +} + //Builds a mapping from old to new ids by skipping values marked invalid template Container compress_ids(const Container& ids) { @@ -162,4 +172,20 @@ ValueContainer update_valid_refs(const ValueContainer& values, const IdContainer return updated; } +template +void update_valid_refs(Iterator begin, Iterator end, const IdContainer& id_map) { + for (auto itr = begin; itr != end; ++itr) { + auto orig_val = *itr; + if (orig_val) { + //Original item valid + + auto new_val = id_map[orig_val]; + if (new_val) { + //The original item exists in the new mapping + *itr = new_val; + } + } + } +} + #endif diff --git a/libs/librrgraph/src/rr_graph_types.h b/libs/librrgraph/src/rr_graph_types.h new file mode 100644 index 000000000..51cf3a0dd --- /dev/null +++ b/libs/librrgraph/src/rr_graph_types.h @@ -0,0 +1,43 @@ +#ifndef RR_GRAPH_TYPES +#define RR_GRAPH_TYPES + +/******************************************************************** + * Data types required by routing resource graph (RRGraph) definition + *******************************************************************/ + +/******************************************************************** + * Directionality of a routing track (node type CHANX and CHANY) in + * a routing resource graph + *******************************************************************/ +enum e_direction : unsigned char { + INC_DIRECTION = 0, + DEC_DIRECTION = 1, + BI_DIRECTION = 2, + NO_DIRECTION = 3, + NUM_DIRECTIONS +}; + +constexpr std::array DIRECTION_STRING = {{"INC_DIRECTION", "DEC_DIRECTION", "BI_DIRECTION", "NO_DIRECTION"}}; + +/* Type of a routing resource node. x-directed channel segment, * + * y-directed channel segment, input pin to a clb to pad, output * + * from a clb or pad (i.e. output pin of a net) and: * + * SOURCE: A dummy node that is a logical output within a block * + * -- i.e., the gate that generates a signal. * + * SINK: A dummy node that is a logical input within a block * + * -- i.e. the gate that needs a signal. */ +typedef enum e_rr_type : unsigned char { + SOURCE = 0, + SINK, + IPIN, + OPIN, + CHANX, + CHANY, + NUM_RR_TYPES +} t_rr_type; + +constexpr std::array RR_TYPES = {{SOURCE, SINK, IPIN, OPIN, CHANX, CHANY}}; +constexpr std::array rr_node_typename{{"SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY"}}; + + +#endif diff --git a/vpr/src/device/rr_graph_util.cpp b/libs/librrgraph/src/rr_graph_util.cpp similarity index 100% rename from vpr/src/device/rr_graph_util.cpp rename to libs/librrgraph/src/rr_graph_util.cpp diff --git a/vpr/src/device/rr_graph_util.h b/libs/librrgraph/src/rr_graph_util.h similarity index 100% rename from vpr/src/device/rr_graph_util.h rename to libs/librrgraph/src/rr_graph_util.h diff --git a/libs/librrgraph/test/test_rr_graph.cpp b/libs/librrgraph/test/test_rr_graph.cpp new file mode 100644 index 000000000..2bd143b81 --- /dev/null +++ b/libs/librrgraph/test/test_rr_graph.cpp @@ -0,0 +1,8 @@ +#include "vtr_geometry.h" +#include "rr_graph_obj.h" + +int main(int argc, char** argv) { + RRGraph rr_graph_obj; + + return 0; +} diff --git a/libs/libvtrutil/src/vtr_geometry.tpp b/libs/libvtrutil/src/vtr_geometry.tpp index 608b09c4c..f0151df2a 100644 --- a/libs/libvtrutil/src/vtr_geometry.tpp +++ b/libs/libvtrutil/src/vtr_geometry.tpp @@ -79,6 +79,12 @@ Rect::Rect(Point bottom_left_val, Point top_right_val) //pass } +template +Rect::Rect() { + //pass +} + + template T Rect::xmin() const { return bottom_left_.x(); diff --git a/vpr/CMakeLists.txt b/vpr/CMakeLists.txt index 4d06b1e1a..217a7bb8d 100644 --- a/vpr/CMakeLists.txt +++ b/vpr/CMakeLists.txt @@ -58,6 +58,7 @@ set_target_properties(libvpr8 PROPERTIES PREFIX "") #Avoid extra 'lib' prefix target_link_libraries(libvpr8 libvtrutil libarchfpga + librrgraph libsdcparse libblifparse libtatum diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index e6c010f73..cb38f75ee 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -40,6 +40,9 @@ #include "vtr_flat_map.h" #include "vtr_cache.h" +/* Header for rr_graph related definition */ +#include "rr_graph_types.h" + /******************************************************************************* * Global data types and constants ******************************************************************************/ @@ -1011,15 +1014,6 @@ struct t_det_routing_arch { std::string write_rr_graph_filename; }; -enum e_direction : unsigned char { - INC_DIRECTION = 0, - DEC_DIRECTION = 1, - BI_DIRECTION = 2, - NO_DIRECTION = 3, - NUM_DIRECTIONS -}; - -constexpr std::array DIRECTION_STRING = {{"INC_DIRECTION", "DEC_DIRECTION", "BI_DIRECTION", "NO_DIRECTION"}}; /* Lists detailed information about segmentation. [0 .. W-1]. * * length: length of segment. * @@ -1132,26 +1126,6 @@ struct t_linked_f_pointer { typedef std::vector>>>> t_rr_node_indices; //[0..num_rr_types-1][0..grid_width-1][0..grid_height-1][0..NUM_SIDES-1][0..max_ptc-1] -/* Type of a routing resource node. x-directed channel segment, * - * y-directed channel segment, input pin to a clb to pad, output * - * from a clb or pad (i.e. output pin of a net) and: * - * SOURCE: A dummy node that is a logical output within a block * - * -- i.e., the gate that generates a signal. * - * SINK: A dummy node that is a logical input within a block * - * -- i.e. the gate that needs a signal. */ -typedef enum e_rr_type : unsigned char { - SOURCE = 0, - SINK, - IPIN, - OPIN, - CHANX, - CHANY, - NUM_RR_TYPES -} t_rr_type; - -constexpr std::array RR_TYPES = {{SOURCE, SINK, IPIN, OPIN, CHANX, CHANY}}; -constexpr std::array rr_node_typename{{"SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY"}}; - /* Basic element used to store the traceback (routing) of each net. * * index: Array index (ID) of this routing resource node. * * iswitch: Index of the switch type used to go from this rr_node to *