@@ -2996,6 +2996,18 @@ void FastRouteCore::setTreeNodesVariables(const int netID)
29962996 auto & treenodes = sttrees_[netID].nodes ;
29972997
29982998 // Setting the values needed for each TreeNode
2999+ //
3000+ // Coordinate deduplication: non-terminal nodes that share a grid (x,y)
3001+ // position with an earlier node are aliased (stackAlias) to that earlier
3002+ // node. The original implementation found the earliest matching node with an
3003+ // O(numpoints) linear scan, making the whole loop O(numpoints^2). For large
3004+ // multi-pin nets this dominates global routing runtime. We replace the scan
3005+ // with a hash-map keyed by the packed (x,y) position, mapping to the dcor
3006+ // index of the FIRST node inserted at that position. This yields identical
3007+ // results (same first-match semantics, same xcor_/ycor_/dcor_ contents)
3008+ // with O(1) average lookups.
3009+ auto & coord_map = tree_node_coord_dedup_;
3010+ coord_map.clear ();
29993011 for (int d = 0 ; d < sttrees_[netID].num_nodes (); d++) {
30003012 treenodes[d].topL = -1 ;
30013013 treenodes[d].botL = num_layers_;
@@ -3006,27 +3018,34 @@ void FastRouteCore::setTreeNodesVariables(const int netID)
30063018 treenodes[d].lID = BIG_INT ;
30073019 treenodes[d].status = 0 ;
30083020
3021+ // Pack the int16_t grid coordinates into a single unsigned 32-bit key.
3022+ // Unsigned avoids undefined behavior from shifting into the sign bit.
3023+ const uint32_t key
3024+ = (static_cast <uint32_t >(static_cast <uint16_t >(treenodes[d].x )) << 16 )
3025+ | static_cast <uint32_t >(static_cast <uint16_t >(treenodes[d].y ));
3026+
30093027 if (d < num_terminals) {
30103028 const int pin_idx = sttrees_[netID].node_to_pin_idx [d];
30113029 treenodes[d].botL = nets_[netID]->getPinL ()[pin_idx];
30123030 treenodes[d].topL = nets_[netID]->getPinL ()[pin_idx];
30133031 treenodes[d].assigned = true ;
30143032 treenodes[d].status = 1 ;
30153033
3034+ // Terminals are always appended (they are never aliased away), matching
3035+ // the original behavior. Record only the first dcor per position so
3036+ // later lookups resolve to the earliest insertion, as the linear scan
3037+ // did.
3038+ coord_map.try_emplace (key, d);
30163039 xcor_[numpoints] = treenodes[d].x ;
30173040 ycor_[numpoints] = treenodes[d].y ;
30183041 dcor_[numpoints] = d;
30193042 numpoints++;
30203043 } else {
3021- bool redundant = false ;
3022- for (int k = 0 ; k < numpoints; k++) {
3023- if ((treenodes[d].x == xcor_[k]) && (treenodes[d].y == ycor_[k])) {
3024- treenodes[d].stackAlias = dcor_[k];
3025- redundant = true ;
3026- break ;
3027- }
3028- }
3029- if (!redundant) {
3044+ const auto it = coord_map.find (key);
3045+ if (it != coord_map.end ()) {
3046+ treenodes[d].stackAlias = it->second ;
3047+ } else {
3048+ coord_map.emplace (key, d);
30303049 xcor_[numpoints] = treenodes[d].x ;
30313050 ycor_[numpoints] = treenodes[d].y ;
30323051 dcor_[numpoints] = d;
0 commit comments