Squashed 'libs/EXTERNAL/libtatum/' changes from 15296d1a4..ee66714ea

ee66714ea Allow nodes with no active (i.e. undisabled) input edges in the first level

git-subtree-dir: libs/EXTERNAL/libtatum
git-subtree-split: ee66714ea4801687083526e0e442c47429dcce76
diff --git a/libtatum/tatum/TimingGraph.cpp b/libtatum/tatum/TimingGraph.cpp
index 0527aa1..f897851 100644
--- a/libtatum/tatum/TimingGraph.cpp
+++ b/libtatum/tatum/TimingGraph.cpp
@@ -125,6 +125,15 @@
                                         size_t max_depth=std::numeric_limits<size_t>::max(), 
                                         size_t depth=0);
 
+size_t TimingGraph::node_num_active_in_edges(const NodeId node) const {
+    size_t active_edges = 0;
+    for (EdgeId edge : node_in_edges(node)) {
+        if (!edge_disabled(edge)) {
+            ++active_edges;
+        }
+    }
+    return active_edges;
+}
 
 EdgeId TimingGraph::node_clock_capture_edge(const NodeId node) const {
 
diff --git a/libtatum/tatum/TimingGraph.hpp b/libtatum/tatum/TimingGraph.hpp
index 887cc2c..77d11ab 100644
--- a/libtatum/tatum/TimingGraph.hpp
+++ b/libtatum/tatum/TimingGraph.hpp
@@ -92,6 +92,9 @@
         ///\returns A range of all in-coming edges the node drives
         edge_range node_in_edges(const NodeId id) const { return tatum::util::make_range(node_in_edges_[id].begin(), node_in_edges_[id].end()); }
 
+        ///\param id The Node id
+        ///\returns The number of active (undisabled) edges terminating at the node
+        size_t node_num_active_in_edges(const NodeId id) const;
 
         ///\param id The node id
         ///\returns The edge id corresponding to the incoming clock capture edge, or EdgeId::INVALID() if none
diff --git a/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp b/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp
index ed1035b..72c9010 100644
--- a/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp
+++ b/libtatum/tatum/graph_visitors/CommonAnalysisVisitor.hpp
@@ -73,7 +73,17 @@
 template<class AnalysisOps>
 bool CommonAnalysisVisitor<AnalysisOps>::do_arrival_pre_traverse_node(const TimingGraph& tg, const TimingConstraints& tc, const NodeId node_id) {
     //Logical Input
-    TATUM_ASSERT_MSG(tg.node_in_edges(node_id).size() == 0, "Logical input has input edges: timing graph not levelized.");
+
+    //We expect this function to only be called on nodes in the first level of the timing graph
+    //These nodes must have no un-disabled input edges (else they shouldn't be in the first level).
+    //In the normal case (primary input) there are no incoming edges. However if set_disable_timing
+    //was used it may be that the edges were explicitly disabled. We therefore verify that there are
+    //no un-disabled edges in the fanin of the current node.
+    TATUM_ASSERT_MSG(tg.node_num_active_in_edges(node_id) == 0, "Logical input has non-disabled input edges: timing graph not levelized.");
+
+    //
+    //We now generate the various clock/data launch tags associated with the arrival time traversal
+    //
 
     NodeType node_type = tg.node_type(node_id);