vpr: Add initial route tree stub check to check_route
diff --git a/vpr/src/route/check_route.cpp b/vpr/src/route/check_route.cpp
index 821ce50..f08d3d6 100755
--- a/vpr/src/route/check_route.cpp
+++ b/vpr/src/route/check_route.cpp
@@ -14,6 +14,8 @@
 #include "rr_graph.h"
 #include "check_rr_graph.h"
 #include "read_xml_arch_file.h"
+#include "route_tree_type.h"
+#include "route_tree_timing.h"
 
 struct t_node_edge {
     t_node_edge(int fnode, int tnode) {
@@ -51,6 +53,11 @@
 static void expand_non_configurable(int inode, std::set<t_node_edge>& edge_set);
 static bool check_non_configurable_edges(ClusterNetId net, const t_non_configurable_rr_sets& non_configurable_rr_sets);
 
+
+void check_net_for_stubs(ClusterNetId net);
+std::vector<t_rt_node*> find_route_tree_stubs(t_rt_node* rt_root);
+bool find_route_tree_stubs_recurr(t_rt_node* rt_root, std::vector<t_rt_node*>& stubs);
+
 /************************ Subroutine definitions ****************************/
 
 void check_route(enum e_route_type route_type) {
@@ -180,6 +187,8 @@
 
         check_non_configurable_edges(net_id, non_configurable_rr_sets);
 
+        check_net_for_stubs(net_id);
+
 		reset_flags(net_id, connected_to_route);
 
 	} /* End for each net */
@@ -880,3 +889,77 @@
 
     return true;
 }
+
+//Cheks for stubs in a net's routing.
+//
+//Stubs (routing branches which don't connect to SINKs) serve no purpose, and only chew up wiring unecessarily.
+//The only exception are stubs required by non-configurable switches (e.g. shorts).
+//
+//We treat any configurable stubs as an error.
+void check_net_for_stubs(ClusterNetId net) {
+    auto& route_ctx = g_vpr_ctx.mutable_routing();
+
+    t_rt_node* rt_root = traceback_to_route_tree(net);
+
+    auto stubs = find_route_tree_stubs(rt_root);
+
+    if (!stubs.empty()) {
+        auto& cluster_ctx = g_vpr_ctx.clustering();
+        std::string msg = vtr::string_fmt("Route tree for net '%s' (#%zu) contains stub branches rooted at:\n",
+                                          cluster_ctx.clb_nlist.net_name(net).c_str(), size_t(net));
+        for (t_rt_node* stub_root : stubs) {
+            msg += vtr::string_fmt("    %s\n", describe_rr_node(stub_root->inode).c_str());
+        }
+
+        VPR_THROW(VPR_ERROR_ROUTE, msg.c_str());
+    }
+
+    free_route_tree(rt_root);
+}
+
+//Returns the set of stub roots for a given route tree
+std::vector<t_rt_node*> find_route_tree_stubs(t_rt_node* rt_root) {
+    std::vector<t_rt_node*> stubs;
+    find_route_tree_stubs_recurr(rt_root, stubs);
+    return stubs;
+}
+
+//Returns true if rt_root is a configurable stub.
+//If any of rt_root's children are stubs they are added to 'stubs' since they are stub roots
+//
+//A stub is defined as a branch of the route tree which does not connect to a SINK, but has
+//configurable edges (and hence should have been trimmed).
+bool find_route_tree_stubs_recurr(t_rt_node* rt_root, std::vector<t_rt_node*>& stubs) {
+    auto& device_ctx = g_vpr_ctx.device();
+
+    if (rt_root->u.child_list == nullptr) {
+        //If a leaf of the route tree is not a SINK, then it is a stub
+        if (device_ctx.rr_nodes[rt_root->inode].type() != SINK) {
+            return true; //It is the current root of this stub
+        } else {
+            return false;
+        }
+    } else {
+        //If any of the children are not stubs, neither is the current node
+        bool is_stub = true;
+        std::vector<t_rt_node*> child_stubs;
+        for (t_linked_rt_edge* edge = rt_root->u.child_list; edge != nullptr; edge = edge->next) {
+            bool child_is_stub = find_route_tree_stubs_recurr(edge->child, stubs);
+            bool driver_switch_configurable = device_ctx.rr_switch_inf[edge->iswitch].configurable();
+
+            if (child_is_stub && driver_switch_configurable) {
+                child_stubs.push_back(edge->child);
+            } else {
+                is_stub = false;
+            }
+        }
+
+        if (is_stub) {
+            return true; //All children were stubs, so is the current node
+        } else {
+            //This node is not a stub, so add any child stubs as stub roots
+            stubs.insert(stubs.end(), child_stubs.begin(), child_stubs.end());
+            return false;
+        }
+    }
+}