@@ -839,26 +839,22 @@ void BinGrid::updateBinsNonPlaceArea()
839839 using boost::polygon::operators::operator +=;
840840 using boost::polygon::operators::operator &=;
841841
842- // Build the union of all non-place instance rectangles. Overlapping
843- // fixed macros (or blockages) would otherwise be double-counted into
844- // the bins they share, pushing density above 100% and producing
845- // artificially large repulsive forces on movable cells.
846- Polygon90Set fixed_set;
847- for (auto & inst : pb_->nonPlaceInsts ()) {
842+ // For each bin, collect indices of non-place instances whose bbox
843+ // overlaps it. The per-bin geometric union (which dedupes overlapping
844+ // fixed macros / blockages) only depends on those instances, so we
845+ // avoid copying a full design-wide polygon set per bin.
846+ const auto & non_place_insts = pb_->nonPlaceInsts ();
847+ std::vector<std::vector<int >> bin_insts (bins_.size ());
848+ for (size_t i = 0 ; i < non_place_insts.size (); ++i) {
849+ const Instance* inst = non_place_insts[i];
848850 if (inst->lx () >= inst->ux () || inst->ly () >= inst->uy ()) {
849851 continue ;
850852 }
851- fixed_set += BoostRect (inst->lx (), inst->ly (), inst->ux (), inst->uy ());
852- }
853-
854- // Identify bins touched by any fixed instance to skip the empty ones.
855- std::vector<bool > touched (bins_.size (), false );
856- for (auto & inst : pb_->nonPlaceInsts ()) {
857853 std::pair<int , int > pairX = getMinMaxIdxX (inst);
858854 std::pair<int , int > pairY = getMinMaxIdxY (inst);
859855 for (int y = pairY.first ; y < pairY.second ; y++) {
860856 for (int x = pairX.first ; x < pairX.second ; x++) {
861- touched [y * binCntX_ + x] = true ;
857+ bin_insts [y * binCntX_ + x]. push_back ( static_cast < int >(i)) ;
862858 }
863859 }
864860 }
@@ -867,13 +863,31 @@ void BinGrid::updateBinsNonPlaceArea()
867863 // fixed instances). Drives nonPlaceAreaUnscaled and the cap below.
868864 std::vector<int64_t > unionArea (bins_.size (), 0 );
869865 for (size_t i = 0 ; i < bins_.size (); ++i) {
870- if (!touched[i]) {
866+ const auto & touching = bin_insts[i];
867+ if (touching.empty ()) {
871868 continue ;
872869 }
873870 Bin& bin = bins_[i];
874- Polygon90Set clip = fixed_set;
875- clip &= BoostRect (bin.lx (), bin.ly (), bin.ux (), bin.uy ());
876- unionArea[i] = boost::polygon::area (clip);
871+ if (touching.size () == 1 ) {
872+ // Single instance: union == clipped overlap, skip Boost.Polygon.
873+ const Instance* inst = non_place_insts[touching.front ()];
874+ const int rectLx = std::max (bin.lx (), inst->lx ());
875+ const int rectLy = std::max (bin.ly (), inst->ly ());
876+ const int rectUx = std::min (bin.ux (), inst->ux ());
877+ const int rectUy = std::min (bin.uy (), inst->uy ());
878+ if (rectLx < rectUx && rectLy < rectUy) {
879+ unionArea[i] = static_cast <int64_t >(rectUx - rectLx)
880+ * static_cast <int64_t >(rectUy - rectLy);
881+ }
882+ } else {
883+ Polygon90Set local_set;
884+ for (int idx : touching) {
885+ const Instance* inst = non_place_insts[idx];
886+ local_set += BoostRect (inst->lx (), inst->ly (), inst->ux (), inst->uy ());
887+ }
888+ local_set &= BoostRect (bin.lx (), bin.ly (), bin.ux (), bin.uy ());
889+ unionArea[i] = boost::polygon::area (local_set);
890+ }
877891 // Note that nonPlaceArea should have scale-down with target
878892 // density. See MS-replace paper.
879893 bin.setNonPlaceAreaUnscaled (
@@ -899,7 +913,7 @@ void BinGrid::updateBinsNonPlaceArea()
899913 }
900914 }
901915 for (size_t i = 0 ; i < bins_.size (); ++i) {
902- if (!touched [i]) {
916+ if (bin_insts [i]. empty () ) {
903917 continue ;
904918 }
905919 Bin& bin = bins_[i];
0 commit comments