diff --git a/.github/actions/build-wheel/action.yml b/.github/actions/build-wheel/action.yml index 2543d095da..7551bad966 100644 --- a/.github/actions/build-wheel/action.yml +++ b/.github/actions/build-wheel/action.yml @@ -15,25 +15,26 @@ runs: flex flex-devel bison eigen3-devel gtest-devel \ tbb-devel hwloc-devel libcurl-devel libunwind-devel \ metis-devel gmp-devel tcl-devel \ - unzip zip + unzip zip bzip2 - - name: Install Boost 1.92.0 + - name: Install Boost 1.91.0 shell: bash run: | - boost_version="1.92.0" - boost_archive="boost-${boost_version}-b2-nodocs.tar.xz" + boost_version="1.91.0" + boost_source_dir="boost_${boost_version//./_}" + boost_archive="${boost_source_dir}.tar.bz2" boost_prefix="${GITHUB_WORKSPACE}/.deps/boost-${boost_version}" - boost_sha256="ea7b982002cc9dfbe59b0b217b206f470dc75f3de0bb2973d844118934d82411" + boost_sha256="de5e6b0e4913395c6bdfa90537febd9028ea4c0735d2cdb0cd9b45d5f51264f5" boost_build_dir="$(mktemp -d)" cd "$boost_build_dir" curl --fail --location --retry 3 --output "$boost_archive" \ - "https://github.com/boostorg/boost/releases/download/boost-${boost_version}/${boost_archive}" + "https://archives.boost.io/release/${boost_version}/source/${boost_archive}" echo "${boost_sha256} ${boost_archive}" | sha256sum --check --status tar -xf "$boost_archive" - cd "boost-${boost_version}" - ./bootstrap.sh --prefix="$boost_prefix" --with-libraries=system - ./b2 -j"$(nproc)" --with-system install + cd "$boost_source_dir" + ./bootstrap.sh --prefix="$boost_prefix" + ./b2 -j"$(nproc)" --with-headers install echo "ECC_BOOST_ROOT=${boost_prefix}" >> "$GITHUB_ENV" @@ -54,9 +55,9 @@ runs: uses: actions/cache@v4 with: path: build - key: cmake-${{ runner.os }}-boost-1.92.0-${{ hashFiles('CMakeLists.txt', 'src/**/CMakeLists.txt') }} + key: cmake-${{ runner.os }}-boost-1.91.0-${{ hashFiles('CMakeLists.txt', 'src/**/CMakeLists.txt') }} restore-keys: | - cmake-${{ runner.os }}-boost-1.92.0- + cmake-${{ runner.os }}-boost-1.91.0- - name: Build repaired wheel shell: bash diff --git a/CMakeLists.txt b/CMakeLists.txt index b5ca4f6d75..1fa137100b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,13 +161,13 @@ SET(THIRD_PARTY_HOME ${HOME_THIRDPARTY}) add_definitions("-DBOOST_ALLOW_DEPRECATED_HEADERS") add_definitions("-DBOOST_BIND_GLOBAL_PLACEHOLDERS") -find_package(Boost 1.92.0 EXACT CONFIG QUIET) +find_package(Boost 1.91.0 EXACT CONFIG QUIET) if(NOT Boost_FOUND) list(FIND Boost_CONSIDERED_VERSIONS "1.85.0" _boost_1_85_index) if(NOT _boost_1_85_index EQUAL -1) - message(FATAL_ERROR "Boost 1.85.0 contains a critical known bug and must not be used. Install Boost 1.92.0 exactly.") + message(FATAL_ERROR "Boost 1.85.0 contains a critical known bug and must not be used. Install Boost 1.91.0 exactly.") endif() - message(FATAL_ERROR "Boost 1.92.0 exactly is required.") + message(FATAL_ERROR "Boost 1.91.0 exactly is required.") endif() include_directories(SYSTEM diff --git a/src/operation/iRT/source/module/planar_router/PlanarRouter.cpp b/src/operation/iRT/source/module/planar_router/PlanarRouter.cpp index 7f93f2566c..21e3620e7f 100644 --- a/src/operation/iRT/source/module/planar_router/PlanarRouter.cpp +++ b/src/operation/iRT/source/module/planar_router/PlanarRouter.cpp @@ -811,7 +811,7 @@ std::vector PlanarRouter::getPRCandidateListByTopo(int32_t expand_s return pr_candidate_list; } -bool PlanarRouter::shouldUseCongestionFlute(double overflow_unit, const PRNet& pr_net, size_t unique_pin_num) +bool PlanarRouter::shouldRefineTopology(double overflow_unit, const PRNet& pr_net, size_t unique_pin_num) { if (unique_pin_num < 3) { return false; @@ -846,9 +846,9 @@ std::vector> PlanarRouter::getPlanarTopoList(double overflo tb_task.set_planar_coord_list(planar_coord_list); GridMap& gcell_map = RTDM.getDatabase().get_gcell_map(); tb_task.set_planar_search_region(PlanarRect(0, 0, gcell_map.get_x_size() - 1, gcell_map.get_y_size() - 1)); - bool congestion_driven = pr_topo_mode == PRTopoMode::kCongestion && shouldUseCongestionFlute(overflow_unit, pr_net, planar_coord_list.size()); - tb_task.set_topo_mode(congestion_driven ? TBTopoMode::kCongestion : TBTopoMode::kGeometry); - if (!congestion_driven) { + bool refine_topology = pr_topo_mode == PRTopoMode::kCongestion && shouldRefineTopology(overflow_unit, pr_net, planar_coord_list.size()); + tb_task.set_topo_mode(refine_topology ? TBTopoMode::kCongestion : TBTopoMode::kGeometry); + if (!refine_topology) { return RTTB.getPlanarTopoList(tb_task); } diff --git a/src/operation/iRT/source/module/planar_router/PlanarRouter.hpp b/src/operation/iRT/source/module/planar_router/PlanarRouter.hpp index 2eee4e0739..f5a1c8ac9b 100644 --- a/src/operation/iRT/source/module/planar_router/PlanarRouter.hpp +++ b/src/operation/iRT/source/module/planar_router/PlanarRouter.hpp @@ -164,7 +164,7 @@ class PlanarRouter std::vector> getOverflowPlanarTopoList(PRNet& pr_net, const std::vector>& unit_segment_list, const std::map, CmpPlanarCoordByXASC>& coord_edge_idx_map, const std::vector& rip_up_distance_list); - bool shouldUseCongestionFlute(double overflow_unit, const PRNet& pr_net, size_t unique_pin_num); + bool shouldRefineTopology(double overflow_unit, const PRNet& pr_net, size_t unique_pin_num); std::vector> getPlanarTopoList(double overflow_unit, PRNet& pr_net, PRTopoMode pr_topo_mode); // A* route diff --git a/src/operation/iRT/source/module/topo_builder/TOPOBuilder.cpp b/src/operation/iRT/source/module/topo_builder/TOPOBuilder.cpp index fc3af4b33b..e61beb6222 100644 --- a/src/operation/iRT/source/module/topo_builder/TOPOBuilder.cpp +++ b/src/operation/iRT/source/module/topo_builder/TOPOBuilder.cpp @@ -30,37 +30,12 @@ using PlanarTopo = std::vector>; using NeighborList = std::vector>; constexpr double kCostEpsilon = 1e-9; -constexpr double kMinWarpStretch = 0.5; -constexpr double kMaxWarpStretch = 8.0; -constexpr double kHotspotWeight = 0.25; -constexpr int64_t kWarpScale = 100; -constexpr int32_t kMaxAxisSampleNum = 64; -constexpr int32_t kMaxThreePinAxisNum = 32; -constexpr int32_t kMaxThreePinCandidateNum = 4096; -constexpr int32_t kThreePinExtraRadius = 2; -constexpr int32_t kMaxRefineAxisNum = 8; -constexpr int32_t kMaxRefinePassNum = 2; constexpr int32_t kMaxSteinerShiftNum = 32; - -enum class TBAxis -{ - kX, - kY -}; - -struct TBGapCostStat -{ - long double finite_cost_sum = 0; - double max_finite_cost = 0; - int64_t edge_num = 0; - int64_t finite_edge_num = 0; - int64_t inf_edge_num = 0; -}; - -struct TBAxisCostStat -{ - std::vector gap_stat_list; -}; +constexpr int32_t kSteinerShiftExactSpan = 16; +constexpr int32_t kSteinerShiftCoarseSampleNum = 8; +constexpr int32_t kSteinerShiftKeepBinNum = 2; +constexpr int32_t kSteinerShiftFineSampleNum = 8; +constexpr int32_t kSteinerShiftLocalRadius = 4; struct TBTopoCandidate { @@ -80,13 +55,6 @@ struct TBSteinerShift bool isValid() const { return first_idx >= 0; } }; -struct TBRefineScore -{ - int32_t inf_edge_num = 0; - double finite_cost = 0; - int64_t wire_length = 0; -}; - int32_t getBranchNum(const Flute::Tree& tree) { return std::max(0, 2 * tree.deg - 2); @@ -221,8 +189,66 @@ void setShiftCoord(PlanarCoord& coord, bool is_horizontal, int32_t value) } } +bool isShiftEdgeEligible(const TBTask& task, const Flute::Tree& tree, const NeighborList& neighbor_list, int32_t first_idx, int32_t second_idx, + const PlanarCoord& first_coord, const PlanarCoord& second_coord) +{ + if (!task.has_shift_edge_filter()) { + return true; + } + if (task.should_shift_edge(first_coord, second_coord)) { + return true; + } + for (int32_t neighbor_idx : neighbor_list[first_idx]) { + if (neighbor_idx != second_idx && task.should_shift_edge(first_coord, getBranchCoord(tree, neighbor_idx))) { + return true; + } + } + for (int32_t neighbor_idx : neighbor_list[second_idx]) { + if (neighbor_idx != first_idx && task.should_shift_edge(second_coord, getBranchCoord(tree, neighbor_idx))) { + return true; + } + } + return false; +} + bool shiftBestSteinerEdge(const TBTask& task, Flute::Tree& tree, const NeighborList& neighbor_list) { + struct ShiftResult + { + bool valid = false; + int32_t value = 0; + double cost = std::numeric_limits::infinity(); + PlanarCoord first_coord; + PlanarCoord second_coord; + }; + + auto make_samples = [](int32_t lower, int32_t upper, int32_t sample_num) { + std::vector samples; + int64_t span = static_cast(upper) - lower + 1; + if (span < sample_num) { + sample_num = static_cast(span); + } + samples.reserve(sample_num); + for (int32_t i = 0; i < sample_num; i++) { + int64_t offset = sample_num == 1 ? 0 : (span - 1) * i / (sample_num - 1); + samples.push_back(static_cast(static_cast(lower) + offset)); + } + return samples; + }; + + auto is_better_result = [](const ShiftResult& first, const ShiftResult& second) { + if (first.valid != second.valid) { + return first.valid; + } + if (!first.valid) { + return false; + } + if (std::abs(first.cost - second.cost) > kCostEpsilon) { + return first.cost < second.cost; + } + return first.value < second.value; + }; + TBSteinerShift best_shift; std::set> visited_edge_set; @@ -254,8 +280,28 @@ bool shiftBestSteinerEdge(const TBTask& task, Flute::Tree& tree, const NeighborL lower = std::max(lower, second_lower); upper = std::min(upper, second_upper); } + if (task.has_planar_search_region()) { + const PlanarRect& region = task.get_planar_search_region(); + if (is_horizontal) { + lower = std::max(lower, region.get_ll_y()); + upper = std::min(upper, region.get_ur_y()); + } else { + lower = std::max(lower, region.get_ll_x()); + upper = std::min(upper, region.get_ur_x()); + } + } + if (lower > upper || !isShiftEdgeEligible(task, tree, neighbor_list, first_idx, second_idx, first_coord, second_coord)) { + continue; + } + PlanarCoord current_movable_coord = first_is_steiner ? first_coord : second_coord; + if (!isInsideSearchRegion(task, current_movable_coord)) { + continue; + } + double current_cost = getIncidentEdgeCost(task, tree, neighbor_list, first_idx, second_idx, first_coord, second_coord); - for (int32_t value = lower; value <= upper; value++) { + + auto get_result = [&](int32_t value) { + ShiftResult result; PlanarCoord candidate_first = first_coord; PlanarCoord candidate_second = second_coord; if (first_is_steiner) { @@ -265,171 +311,97 @@ bool shiftBestSteinerEdge(const TBTask& task, Flute::Tree& tree, const NeighborL setShiftCoord(candidate_second, is_horizontal, value); } PlanarCoord movable_coord = first_is_steiner ? candidate_first : candidate_second; - PlanarCoord current_movable_coord = first_is_steiner ? first_coord : second_coord; - if (movable_coord == current_movable_coord || !isInsideSearchRegion(task, movable_coord)) { - continue; + if (movable_coord == current_movable_coord) { + result.valid = true; + result.value = value; + result.cost = current_cost; + result.first_coord = first_coord; + result.second_coord = second_coord; + return result; } - double candidate_cost = getIncidentEdgeCost(task, tree, neighbor_list, first_idx, second_idx, candidate_first, candidate_second); - if (!isStrictlyBetterCost(current_cost, candidate_cost)) { - continue; + result.valid = true; + result.value = value; + result.cost = getIncidentEdgeCost(task, tree, neighbor_list, first_idx, second_idx, candidate_first, candidate_second); + result.first_coord = candidate_first; + result.second_coord = candidate_second; + return result; + }; + + auto consider_result = [&](const ShiftResult& result) { + if (!result.valid || !isStrictlyBetterCost(current_cost, result.cost)) { + return; } - double gain = std::isfinite(current_cost) ? current_cost - candidate_cost : std::numeric_limits::infinity(); + double gain = std::isfinite(current_cost) ? current_cost - result.cost : std::numeric_limits::infinity(); if (!best_shift.isValid() || gain > best_shift.gain + kCostEpsilon) { - best_shift = {first_idx, second_idx, candidate_first, candidate_second, gain}; + best_shift = {first_idx, second_idx, result.first_coord, result.second_coord, gain}; } - } - } - if (best_shift.isValid()) { - setBranchCoord(tree, best_shift.first_idx, best_shift.first_coord); - setBranchCoord(tree, best_shift.second_idx, best_shift.second_coord); - } - return best_shift.isValid(); -} - -int32_t compareRefineScore(const TBRefineScore& first, const TBRefineScore& second) -{ - if (first.inf_edge_num != second.inf_edge_num) { - return first.inf_edge_num < second.inf_edge_num ? -1 : 1; - } - if (std::abs(first.finite_cost - second.finite_cost) > kCostEpsilon) { - return first.finite_cost < second.finite_cost ? -1 : 1; - } - if (first.wire_length != second.wire_length) { - return first.wire_length < second.wire_length ? -1 : 1; - } - return 0; -} + }; -std::vector getRefineAxisList(int32_t lower, int32_t upper, int32_t current, const std::vector& neighbor_axis_list) -{ - std::set axis_set{std::clamp(current, lower, upper)}; - for (int32_t value : neighbor_axis_list) { - if (lower <= value && value <= upper && axis_set.size() < kMaxRefineAxisNum) { - axis_set.insert(value); - } - } - int32_t sample_num = kMaxRefineAxisNum - static_cast(axis_set.size()); - int64_t span = static_cast(upper) - lower; - for (int32_t sample_idx = 0; sample_idx < sample_num; sample_idx++) { - int64_t offset = sample_num <= 1 ? span / 2 : span * sample_idx / (sample_num - 1); - axis_set.insert(static_cast(lower + offset)); - } - return {axis_set.begin(), axis_set.end()}; -} - -TBRefineScore getSteinerScore(const TBTask& task, const Flute::Tree& tree, const NeighborList& neighbor_list, const std::vector& branch_idx_list, - const PlanarCoord& candidate) -{ - std::set branch_idx_set(branch_idx_list.begin(), branch_idx_list.end()); - std::set> edge_set; - TBRefineScore score; - for (int32_t branch_idx : branch_idx_list) { - for (int32_t neighbor_idx : neighbor_list[branch_idx]) { - if (!branch_idx_set.contains(neighbor_idx)) { - edge_set.emplace(std::min(branch_idx, neighbor_idx), std::max(branch_idx, neighbor_idx)); + int64_t span = static_cast(upper) - lower + 1; + if (span <= kSteinerShiftExactSpan) { + for (int32_t value = lower; value <= upper; value++) { + consider_result(get_result(value)); } + continue; } - } - for (const auto& [first_idx, second_idx] : edge_set) { - int32_t neighbor_idx = branch_idx_set.contains(first_idx) ? second_idx : first_idx; - PlanarCoord neighbor = getBranchCoord(tree, neighbor_idx); - double cost = getPatternCost(task, candidate, neighbor); - if (std::isfinite(cost)) { - score.finite_cost += cost; - } else { - score.inf_edge_num++; - } - score.wire_length - += std::abs(static_cast(candidate.get_x()) - neighbor.get_x()) + std::abs(static_cast(candidate.get_y()) - neighbor.get_y()); - } - return score; -} -std::vector getSteinerCandidateList(const TBTask& task, const Flute::Tree& tree, const NeighborList& neighbor_list, - const std::vector& branch_idx_list) -{ - PlanarCoord current = getBranchCoord(tree, branch_idx_list.front()); - int32_t ll_x = current.get_x(); - int32_t ur_x = current.get_x(); - int32_t ll_y = current.get_y(); - int32_t ur_y = current.get_y(); - for (const PlanarCoord& terminal : task.get_planar_coord_list()) { - ll_x = std::min(ll_x, terminal.get_x()); - ur_x = std::max(ur_x, terminal.get_x()); - ll_y = std::min(ll_y, terminal.get_y()); - ur_y = std::max(ur_y, terminal.get_y()); - } - if (task.has_planar_search_region()) { - const PlanarRect& region = task.get_planar_search_region(); - ll_x = std::max(ll_x, region.get_ll_x()); - ur_x = std::min(ur_x, region.get_ur_x()); - ll_y = std::max(ll_y, region.get_ll_y()); - ur_y = std::min(ur_y, region.get_ur_y()); - } - - std::vector neighbor_x_list; - std::vector neighbor_y_list; - for (int32_t branch_idx : branch_idx_list) { - for (int32_t neighbor_idx : neighbor_list[branch_idx]) { - PlanarCoord neighbor = getBranchCoord(tree, neighbor_idx); - neighbor_x_list.push_back(neighbor.get_x()); - neighbor_y_list.push_back(neighbor.get_y()); - } - } - std::vector x_list = getRefineAxisList(ll_x, ur_x, current.get_x(), neighbor_x_list); - std::vector y_list = getRefineAxisList(ll_y, ur_y, current.get_y(), neighbor_y_list); - std::vector candidate_list; - candidate_list.reserve(x_list.size() * y_list.size()); - for (int32_t x : x_list) { - for (int32_t y : y_list) { - PlanarCoord candidate(x, y); - if (candidate != current && isInsideSearchRegion(task, candidate)) { - candidate_list.push_back(candidate); + struct ShiftBin + { + int32_t lower; + int32_t upper; + ShiftResult coarse; + }; + std::vector coarse_samples = make_samples(lower, upper, kSteinerShiftCoarseSampleNum); + std::vector bins; + bins.reserve(coarse_samples.size()); + for (size_t i = 0; i < coarse_samples.size(); i++) { + int32_t bin_lower = i == 0 ? lower : static_cast(static_cast(coarse_samples[i - 1]) + + (static_cast(coarse_samples[i]) - coarse_samples[i - 1]) / 2 + 1); + int32_t bin_upper = i + 1 == coarse_samples.size() ? upper : static_cast(static_cast(coarse_samples[i]) + + (static_cast(coarse_samples[i + 1]) - coarse_samples[i]) / 2); + ShiftResult coarse = get_result(coarse_samples[i]); + consider_result(coarse); + bins.push_back({bin_lower, bin_upper, coarse}); + } + std::ranges::sort(bins, [&](const ShiftBin& first, const ShiftBin& second) { + if (is_better_result(first.coarse, second.coarse)) { + return true; } - } - } - return candidate_list; -} - -void refineSteinerByCost(const TBTask& task, Flute::Tree& tree, TBRefineStat& stat) -{ - NeighborList neighbor_list = getNeighborList(tree); - for (int32_t pass = 0; pass < kMaxRefinePassNum; pass++) { - std::map, CmpPlanarCoordByXASC> coord_branch_map; - for (int32_t branch_idx = tree.deg; branch_idx < getBranchNum(tree); branch_idx++) { - coord_branch_map[getBranchCoord(tree, branch_idx)].push_back(branch_idx); - } - bool moved = false; - for (const auto& [current, branch_idx_list] : coord_branch_map) { - if (getBranchCoord(tree, branch_idx_list.front()) != current) { - continue; + if (is_better_result(second.coarse, first.coarse)) { + return false; } - TBRefineScore best_score = getSteinerScore(task, tree, neighbor_list, branch_idx_list, current); - PlanarCoord best_coord = current; - for (const PlanarCoord& candidate : getSteinerCandidateList(task, tree, neighbor_list, branch_idx_list)) { - TBRefineScore candidate_score = getSteinerScore(task, tree, neighbor_list, branch_idx_list, candidate); - int32_t score_cmp = compareRefineScore(candidate_score, best_score); - if (score_cmp < 0 || (score_cmp == 0 && best_coord != current && CmpPlanarCoordByXASC()(candidate, best_coord))) { - best_score = candidate_score; - best_coord = candidate; + return first.lower < second.lower; + }); + + int32_t bin_num = std::min(kSteinerShiftKeepBinNum, static_cast(bins.size())); + for (int32_t bin_idx = 0; bin_idx < bin_num; bin_idx++) { + ShiftBin& bin = bins[bin_idx]; + ShiftResult bin_best = bin.coarse; + for (int32_t value : make_samples(bin.lower, bin.upper, kSteinerShiftFineSampleNum)) { + ShiftResult result = get_result(value); + consider_result(result); + if (is_better_result(result, bin_best)) { + bin_best = result; } } - if (best_coord == current) { + if (!bin_best.valid) { continue; } - for (int32_t branch_idx : branch_idx_list) { - setBranchCoord(tree, branch_idx, best_coord); + int32_t local_lower = static_cast(std::max(bin.lower, static_cast(bin_best.value) - kSteinerShiftLocalRadius)); + int32_t local_upper = static_cast(std::min(bin.upper, static_cast(bin_best.value) + kSteinerShiftLocalRadius)); + for (int32_t value = local_lower; value <= local_upper; value++) { + consider_result(get_result(value)); } - stat.refined_steiner_num++; - moved = true; - } - if (!moved) { - break; } } + if (best_shift.isValid()) { + setBranchCoord(tree, best_shift.first_idx, best_shift.first_coord); + setBranchCoord(tree, best_shift.second_idx, best_shift.second_coord); + } + return best_shift.isValid(); } -void refineFluteTree(const TBTask& task, Flute::Tree& tree, TBRefineStat& stat, bool enable_steiner_refine) +void shiftSteinerEdgesByCost(const TBTask& task, Flute::Tree& tree, TBRefineStat& stat) { if (!task.has_segment_cost_query() || !task.is_cost_refine_enabled()) { return; @@ -439,171 +411,6 @@ void refineFluteTree(const TBTask& task, Flute::Tree& tree, TBRefineStat& stat, while (stat.shifted_edge_num < max_shift_num && shiftBestSteinerEdge(task, tree, neighbor_list)) { stat.shifted_edge_num++; } - if (enable_steiner_refine && task.is_congestion_driven()) { - refineSteinerByCost(task, tree, stat); - } -} - -std::vector getUniqueAxisList(const std::vector& coord_list, TBAxis axis) -{ - std::vector axis_list; - axis_list.reserve(coord_list.size()); - for (const PlanarCoord& coord : coord_list) { - axis_list.push_back(axis == TBAxis::kX ? coord.get_x() : coord.get_y()); - } - std::ranges::sort(axis_list); - axis_list.erase(std::ranges::unique(axis_list).begin(), axis_list.end()); - return axis_list; -} - -std::vector getSampleCoordList(const std::vector& axis) -{ - int64_t span = static_cast(axis.back()) - axis.front(); - if (span + 1 <= kMaxAxisSampleNum) { - std::vector sample_list; - sample_list.reserve(span + 1); - for (int64_t coord = axis.front(); coord <= axis.back(); coord++) { - sample_list.push_back(static_cast(coord)); - } - return sample_list; - } - std::set sample_set; - for (int32_t coord : axis) { - for (int32_t offset : {-1, 0, 1}) { - int64_t sample = static_cast(coord) + offset; - if (axis.front() <= sample && sample <= axis.back()) { - sample_set.insert(static_cast(sample)); - } - } - } - if (sample_set.size() > kMaxAxisSampleNum) { - std::vector mandatory_list(sample_set.begin(), sample_set.end()); - sample_set.clear(); - for (int32_t sample_idx = 0; sample_idx < kMaxAxisSampleNum; sample_idx++) { - size_t index = mandatory_list.size() == 1 - ? 0 - : static_cast(sample_idx) * (mandatory_list.size() - 1) / (kMaxAxisSampleNum - 1); - sample_set.insert(mandatory_list[index]); - } - return {sample_set.begin(), sample_set.end()}; - } - int32_t sample_num = std::max(0, kMaxAxisSampleNum - static_cast(sample_set.size())); - for (int32_t sample_idx = 0; sample_idx < sample_num; sample_idx++) { - int64_t offset = sample_num == 1 ? span / 2 : span * sample_idx / (sample_num - 1); - sample_set.insert(static_cast(axis.front() + offset)); - } - return {sample_set.begin(), sample_set.end()}; -} - -TBAxisCostStat getAxisCostStat(const TBTask& task, const std::vector& axis, const std::vector& orth_axis, TBAxis direction) -{ - TBAxisCostStat stat; - if (axis.size() <= 1 || orth_axis.empty()) { - return stat; - } - size_t gap_num = axis.size() - 1; - stat.gap_stat_list.resize(gap_num); - std::vector sample_coord_list = getSampleCoordList(orth_axis); - bool is_horizontal = direction == TBAxis::kX; - for (size_t gap_idx = 0; gap_idx < gap_num; gap_idx++) { - TBGapCostStat& gap_stat = stat.gap_stat_list[gap_idx]; - for (int64_t axis_coord = axis[gap_idx]; axis_coord < axis[gap_idx + 1]; axis_coord++) { - for (int32_t orth_coord : sample_coord_list) { - PlanarCoord first - = is_horizontal ? PlanarCoord(static_cast(axis_coord), orth_coord) : PlanarCoord(orth_coord, static_cast(axis_coord)); - PlanarCoord second - = is_horizontal ? PlanarCoord(static_cast(axis_coord + 1), orth_coord) : PlanarCoord(orth_coord, static_cast(axis_coord + 1)); - double cost = getSegmentCost(task, first, second); - gap_stat.edge_num++; - if (!std::isfinite(cost)) { - gap_stat.inf_edge_num++; - continue; - } - gap_stat.finite_cost_sum += cost; - gap_stat.max_finite_cost = std::max(gap_stat.max_finite_cost, cost); - gap_stat.finite_edge_num++; - } - } - } - return stat; -} - -double getGapDensity(const TBGapCostStat& gap_stat, double reference_cost) -{ - if (gap_stat.edge_num == 0 || gap_stat.finite_edge_num == 0) { - return std::numeric_limits::infinity(); - } - double mean_cost = gap_stat.finite_cost_sum / gap_stat.finite_edge_num; - double blocked_ratio = gap_stat.inf_edge_num / static_cast(gap_stat.edge_num); - return mean_cost + kHotspotWeight * gap_stat.max_finite_cost + blocked_ratio * reference_cost * kMaxWarpStretch; -} - -double getReferenceCost(const TBAxisCostStat& x_stat, const TBAxisCostStat& y_stat) -{ - std::vector cost_list; - for (const TBAxisCostStat* stat : {&x_stat, &y_stat}) { - for (const TBGapCostStat& gap_stat : stat->gap_stat_list) { - if (gap_stat.finite_edge_num == 0) { - continue; - } - double cost = gap_stat.finite_cost_sum / gap_stat.finite_edge_num + kHotspotWeight * gap_stat.max_finite_cost; - if (cost > kCostEpsilon) { - cost_list.push_back(cost); - } - } - } - if (cost_list.empty()) { - return std::numeric_limits::infinity(); - } - auto middle = cost_list.begin() + cost_list.size() / 2; - std::ranges::nth_element(cost_list, middle); - return *middle; -} - -bool buildWarpedAxis(const std::vector& raw_axis, const TBAxisCostStat& cost_stat, double reference_cost, - std::vector& warped_axis) -{ - if (raw_axis.empty()) { - return false; - } - warped_axis.assign(raw_axis.size(), 0); - constexpr int64_t max_warp_coord = std::numeric_limits::max() / 4; - for (size_t gap_idx = 0; gap_idx + 1 < raw_axis.size(); gap_idx++) { - const TBGapCostStat& gap_stat = cost_stat.gap_stat_list[gap_idx]; - double density = getGapDensity(gap_stat, reference_cost); - if (!std::isfinite(density)) { - return false; - } - double stretch = std::clamp(density / reference_cost, kMinWarpStretch, kMaxWarpStretch); - int64_t axis_delta = static_cast(raw_axis[gap_idx + 1]) - raw_axis[gap_idx]; - long double raw_delta = static_cast(axis_delta) * kWarpScale * stretch; - if (!std::isfinite(raw_delta) || raw_delta > max_warp_coord - warped_axis[gap_idx]) { - return false; - } - int64_t warped_delta = std::max(1, std::llround(raw_delta)); - warped_axis[gap_idx + 1] = static_cast(warped_axis[gap_idx] + warped_delta); - } - return true; -} - -int32_t getAxisIndex(const std::vector& axis, int32_t value) -{ - auto iter = std::ranges::lower_bound(axis, value); - return iter != axis.end() && *iter == value ? static_cast(iter - axis.begin()) : -1; -} - -bool restoreRawCoordinates(Flute::Tree& tree, const std::vector& raw_x_axis, const std::vector& raw_y_axis, - const std::vector& warped_x_axis, const std::vector& warped_y_axis) -{ - for (int32_t branch_idx = 0; branch_idx < getBranchNum(tree); branch_idx++) { - int32_t x_idx = getAxisIndex(warped_x_axis, tree.branch[branch_idx].x); - int32_t y_idx = getAxisIndex(warped_y_axis, tree.branch[branch_idx].y); - if (x_idx < 0 || y_idx < 0 || tree.branch[branch_idx].n < 0 || getBranchNum(tree) <= tree.branch[branch_idx].n) { - return false; - } - setBranchCoord(tree, branch_idx, PlanarCoord(raw_x_axis[x_idx], raw_y_axis[y_idx])); - } - return true; } PlanarTopo getTopoListByTree(const Flute::Tree& tree) @@ -633,53 +440,16 @@ double getTopoCost(const TBTask& task, const PlanarTopo& topo_list) return cost; } -PlanarTopo getThreePinTopo(const std::vector& terminal_list, const PlanarCoord& steiner) -{ - PlanarTopo topo_list; - topo_list.reserve(terminal_list.size()); - for (const PlanarCoord& terminal : terminal_list) { - if (terminal != steiner) { - topo_list.emplace_back(terminal, steiner); - } - } - return topo_list; -} - -std::vector getCandidateAxisList(int32_t lower, int32_t upper, std::vector mandatory_list) -{ - std::erase_if(mandatory_list, [&](int32_t coord) { return coord < lower || upper < coord; }); - std::ranges::sort(mandatory_list); - mandatory_list.erase(std::ranges::unique(mandatory_list).begin(), mandatory_list.end()); - - int64_t span = static_cast(upper) - lower; - if (span + 1 <= kMaxThreePinAxisNum) { - mandatory_list.clear(); - for (int64_t coord = lower; coord <= upper; coord++) { - mandatory_list.push_back(static_cast(coord)); - } - return mandatory_list; - } - - int32_t sample_num = std::max(0, kMaxThreePinAxisNum - static_cast(mandatory_list.size())); - for (int32_t sample_idx = 0; sample_idx < sample_num; sample_idx++) { - int64_t offset = sample_num <= 1 ? span / 2 : span * sample_idx / (sample_num - 1); - mandatory_list.push_back(static_cast(lower + offset)); - } - std::ranges::sort(mandatory_list); - mandatory_list.erase(std::ranges::unique(mandatory_list).begin(), mandatory_list.end()); - return mandatory_list; -} - -TBTopoCandidate finalizeCandidate(const TBTask& task, Flute::Tree& tree, bool enable_steiner_refine) +TBTopoCandidate finalizeCandidate(const TBTask& task, Flute::Tree& tree) { TBTopoCandidate candidate; - refineFluteTree(task, tree, candidate.refine_stat, enable_steiner_refine); + shiftSteinerEdgesByCost(task, tree, candidate.refine_stat); candidate.topo_list = getTopoListByTree(tree); candidate.cost = getTopoCost(task, candidate.topo_list); return candidate; } -TBTopoCandidate buildBaselineCandidate(const TBTask& task, bool enable_steiner_refine) +TBTopoCandidate buildBaselineCandidate(const TBTask& task) { const std::vector& coord_list = task.get_planar_coord_list(); std::vector x_list(coord_list.size()); @@ -689,7 +459,7 @@ TBTopoCandidate buildBaselineCandidate(const TBTask& task, bool enable_steiner_r y_list[coord_idx] = coord_list[coord_idx].get_y(); } Flute::Tree tree = Flute::flute(static_cast(coord_list.size()), x_list.data(), y_list.data(), FLUTE_ACCURACY); - TBTopoCandidate candidate = finalizeCandidate(task, tree, enable_steiner_refine); + TBTopoCandidate candidate = finalizeCandidate(task, tree); Flute::free_tree(tree); return candidate; } @@ -756,147 +526,6 @@ TBTopoCandidate buildTerminalMSTCandidate(const TBTask& task) return candidate; } -std::optional buildThreePinCongestionCandidate(const TBTask& task) -{ - const std::vector& terminal_list = task.get_planar_coord_list(); - int32_t ll_x = terminal_list.front().get_x(); - int32_t ur_x = ll_x; - int32_t ll_y = terminal_list.front().get_y(); - int32_t ur_y = ll_y; - - std::vector terminal_x_list; - std::vector terminal_y_list; - for (const PlanarCoord& terminal : terminal_list) { - ll_x = std::min(ll_x, terminal.get_x()); - ur_x = std::max(ur_x, terminal.get_x()); - ll_y = std::min(ll_y, terminal.get_y()); - ur_y = std::max(ur_y, terminal.get_y()); - terminal_x_list.push_back(terminal.get_x()); - terminal_y_list.push_back(terminal.get_y()); - } - std::vector candidate_x_list = getCandidateAxisList(ll_x, ur_x, terminal_x_list); - std::vector candidate_y_list = getCandidateAxisList(ll_y, ur_y, terminal_y_list); - - std::optional best_candidate; - PlanarCoord best_steiner; - int64_t best_wire_length = std::numeric_limits::max(); - int32_t candidate_num = 0; - std::unordered_set visited_set; - visited_set.reserve(kMaxThreePinCandidateNum); - auto evaluateCandidate = [&](const PlanarCoord& steiner) { - uint64_t coord_key = (static_cast(static_cast(steiner.get_x())) << 32) | static_cast(steiner.get_y()); - if (candidate_num >= kMaxThreePinCandidateNum || !isInsideSearchRegion(task, steiner) || !visited_set.insert(coord_key).second) { - return; - } - candidate_num++; - double cost = 0; - int64_t wire_length = 0; - for (const PlanarCoord& terminal : terminal_list) { - if (terminal == steiner) { - continue; - } - double pattern_cost = getPatternCost(task, terminal, steiner); - if (!std::isfinite(pattern_cost)) { - return; - } - cost += pattern_cost; - wire_length += std::abs(static_cast(terminal.get_x()) - steiner.get_x()) + std::abs(static_cast(terminal.get_y()) - steiner.get_y()); - if (best_candidate.has_value() && cost > best_candidate->cost + kCostEpsilon) { - return; - } - } - bool has_equal_cost = best_candidate.has_value() && std::abs(cost - best_candidate->cost) <= kCostEpsilon; - bool is_better - = !best_candidate.has_value() || isStrictlyBetterCost(best_candidate->cost, cost) - || (has_equal_cost && (wire_length < best_wire_length || (wire_length == best_wire_length && CmpPlanarCoordByXASC()(steiner, best_steiner)))); - if (is_better) { - best_candidate = TBTopoCandidate{.topo_list = getThreePinTopo(terminal_list, steiner), .cost = cost}; - best_steiner = steiner; - best_wire_length = wire_length; - } - }; - - for (int32_t x : candidate_x_list) { - for (int32_t y : candidate_y_list) { - evaluateCandidate(PlanarCoord(x, y)); - } - } - if (best_candidate.has_value() || !task.has_planar_search_region()) { - return best_candidate; - } - - const PlanarRect& region = task.get_planar_search_region(); - int32_t max_radius = std::max({ll_x - region.get_ll_x(), region.get_ur_x() - ur_x, ll_y - region.get_ll_y(), region.get_ur_y() - ur_y}); - int32_t found_radius = -1; - for (int32_t radius = 1; - radius <= max_radius && candidate_num < kMaxThreePinCandidateNum && (found_radius == -1 || radius <= found_radius + kThreePinExtraRadius); radius++) { - int32_t expanded_ll_x = std::max(region.get_ll_x(), ll_x - radius); - int32_t expanded_ur_x = std::min(region.get_ur_x(), ur_x + radius); - int32_t expanded_ll_y = std::max(region.get_ll_y(), ll_y - radius); - int32_t expanded_ur_y = std::min(region.get_ur_y(), ur_y + radius); - for (int64_t x = expanded_ll_x; x <= expanded_ur_x && candidate_num < kMaxThreePinCandidateNum; x++) { - evaluateCandidate(PlanarCoord(static_cast(x), expanded_ll_y)); - evaluateCandidate(PlanarCoord(static_cast(x), expanded_ur_y)); - } - for (int64_t y = static_cast(expanded_ll_y) + 1; y < expanded_ur_y && candidate_num < kMaxThreePinCandidateNum; y++) { - evaluateCandidate(PlanarCoord(expanded_ll_x, static_cast(y))); - evaluateCandidate(PlanarCoord(expanded_ur_x, static_cast(y))); - } - if (found_radius == -1 && best_candidate.has_value()) { - found_radius = radius; - } - } - return best_candidate; -} - -std::optional buildWarpedCongestionCandidate(const TBTask& task) -{ - const std::vector& coord_list = task.get_planar_coord_list(); - std::vector raw_x_axis = getUniqueAxisList(coord_list, TBAxis::kX); - std::vector raw_y_axis = getUniqueAxisList(coord_list, TBAxis::kY); - constexpr int64_t max_warp_coord = std::numeric_limits::max() / 4; - auto is_axis_warpable = [](const std::vector& axis) { - int64_t span = static_cast(axis.back()) - axis.front(); - return span <= max_warp_coord / kWarpScale; - }; - if (!is_axis_warpable(raw_x_axis) || !is_axis_warpable(raw_y_axis)) { - return std::nullopt; - } - TBAxisCostStat x_cost_stat = getAxisCostStat(task, raw_x_axis, raw_y_axis, TBAxis::kX); - TBAxisCostStat y_cost_stat = getAxisCostStat(task, raw_y_axis, raw_x_axis, TBAxis::kY); - double reference_cost = getReferenceCost(x_cost_stat, y_cost_stat); - if (!std::isfinite(reference_cost)) { - return std::nullopt; - } - - std::vector warped_x_axis; - std::vector warped_y_axis; - if (!buildWarpedAxis(raw_x_axis, x_cost_stat, reference_cost, warped_x_axis) || !buildWarpedAxis(raw_y_axis, y_cost_stat, reference_cost, warped_y_axis)) { - return std::nullopt; - } - - std::vector x_list(coord_list.size()); - std::vector y_list(coord_list.size()); - for (size_t coord_idx = 0; coord_idx < coord_list.size(); coord_idx++) { - x_list[coord_idx] = warped_x_axis[getAxisIndex(raw_x_axis, coord_list[coord_idx].get_x())]; - y_list[coord_idx] = warped_y_axis[getAxisIndex(raw_y_axis, coord_list[coord_idx].get_y())]; - } - - Flute::Tree tree = Flute::flute(static_cast(coord_list.size()), x_list.data(), y_list.data(), FLUTE_ACCURACY); - bool is_mapped = restoreRawCoordinates(tree, raw_x_axis, raw_y_axis, warped_x_axis, warped_y_axis); - TBTopoCandidate candidate; - if (is_mapped) { - candidate = finalizeCandidate(task, tree, false); - } - Flute::free_tree(tree); - return is_mapped ? std::optional(std::move(candidate)) : std::nullopt; -} - -std::optional buildCongestionCandidate(const TBTask& task) -{ - return task.get_planar_coord_list().size() == 3 ? buildThreePinCongestionCandidate(task) : buildWarpedCongestionCandidate(task); -} - } // namespace // public @@ -952,36 +581,13 @@ std::vector> TOPOBuilder::getPlanarTopoList(const TBTask& t return {Segment(coord_list.front(), coord_list.back())}; } - bool attempted_congestion_flute = task.is_congestion_driven() && coord_list.size() >= 3 && task.has_segment_cost_query(); - TBTopoCandidate selected_candidate = buildBaselineCandidate(task, false); - bool used_congestion_flute = false; - if (attempted_congestion_flute) { - std::optional congestion_candidate = buildCongestionCandidate(task); - if (congestion_candidate.has_value() && isStrictlyBetterCost(selected_candidate.cost, congestion_candidate->cost)) { - selected_candidate = std::move(*congestion_candidate); - used_congestion_flute = true; - } - } - bool attempted_steiner_refine = false; - bool used_steiner_refine = false; - if (attempted_congestion_flute && coord_list.size() > 3 && !std::isfinite(selected_candidate.cost)) { - attempted_steiner_refine = true; - TBTopoCandidate refined_candidate = buildBaselineCandidate(task, true); - if (std::isfinite(refined_candidate.cost)) { - selected_candidate = std::move(refined_candidate); - used_steiner_refine = true; - } - } - bool used_terminal_mst = attempted_congestion_flute && !std::isfinite(selected_candidate.cost); + TBTopoCandidate selected_candidate = buildBaselineCandidate(task); + bool used_terminal_mst = task.is_congestion_driven() && task.has_segment_cost_query() && !std::isfinite(selected_candidate.cost); if (used_terminal_mst) { selected_candidate = buildTerminalMSTCandidate(task); } stat = selected_candidate.refine_stat; - stat.attempted_congestion_flute = attempted_congestion_flute; - stat.used_congestion_flute = used_congestion_flute; - stat.attempted_steiner_refine = attempted_steiner_refine; - stat.used_steiner_refine = used_steiner_refine; stat.used_terminal_mst = used_terminal_mst; return std::move(selected_candidate.topo_list); } diff --git a/src/operation/iRT/source/module/topo_builder/TOPOBuilder.hpp b/src/operation/iRT/source/module/topo_builder/TOPOBuilder.hpp index 39e763781c..be1e99fdfd 100644 --- a/src/operation/iRT/source/module/topo_builder/TOPOBuilder.hpp +++ b/src/operation/iRT/source/module/topo_builder/TOPOBuilder.hpp @@ -26,11 +26,6 @@ namespace irt { struct TBRefineStat { int32_t shifted_edge_num = 0; - int32_t refined_steiner_num = 0; - bool attempted_congestion_flute = false; - bool used_congestion_flute = false; - bool attempted_steiner_refine = false; - bool used_steiner_refine = false; bool used_terminal_mst = false; }; diff --git a/src/operation/iRT/source/module/topo_builder/tb_data_manager/TBTask.hpp b/src/operation/iRT/source/module/topo_builder/tb_data_manager/TBTask.hpp index b7c19e013d..a76129e30e 100644 --- a/src/operation/iRT/source/module/topo_builder/tb_data_manager/TBTask.hpp +++ b/src/operation/iRT/source/module/topo_builder/tb_data_manager/TBTask.hpp @@ -23,6 +23,7 @@ namespace irt { using TBSegmentCostQuery = std::function; +using TBShiftEdgeFilter = std::function; enum class TBTopoMode { @@ -42,12 +43,14 @@ class TBTask const PlanarRect& get_planar_search_region() const { return _planar_search_region; } bool has_planar_search_region() const { return _has_planar_search_region; } bool has_segment_cost_query() const { return static_cast(_segment_cost_query); } + bool has_shift_edge_filter() const { return static_cast(_shift_edge_filter); } TBTopoMode get_topo_mode() const { return _topo_mode; } bool is_cost_refine_enabled() const { return _topo_mode != TBTopoMode::kGeometry; } bool is_congestion_driven() const { return _topo_mode == TBTopoMode::kCongestion; } // setter void set_planar_coord_list(std::vector planar_coord_list) { _planar_coord_list = std::move(planar_coord_list); } void set_segment_cost_query(TBSegmentCostQuery query) { _segment_cost_query = std::move(query); } + void set_shift_edge_filter(TBShiftEdgeFilter filter) { _shift_edge_filter = std::move(filter); } void set_topo_mode(TBTopoMode topo_mode) { _topo_mode = topo_mode; } void set_congestion_driven(bool congestion_driven) { @@ -60,10 +63,12 @@ class TBTask } // function double get_segment_cost(const PlanarCoord& first, const PlanarCoord& second) const { return _segment_cost_query(first, second); } + bool should_shift_edge(const PlanarCoord& first, const PlanarCoord& second) const { return _shift_edge_filter(first, second); } private: std::vector _planar_coord_list; TBSegmentCostQuery _segment_cost_query; + TBShiftEdgeFilter _shift_edge_filter; PlanarRect _planar_search_region; bool _has_planar_search_region = false; TBTopoMode _topo_mode = TBTopoMode::kGeometry; diff --git a/src/operation/iRT/test/test_topo_builder/test_topo_builder.cpp b/src/operation/iRT/test/test_topo_builder/test_topo_builder.cpp index aa63931d11..46a7a760a6 100644 --- a/src/operation/iRT/test/test_topo_builder/test_topo_builder.cpp +++ b/src/operation/iRT/test/test_topo_builder/test_topo_builder.cpp @@ -207,10 +207,7 @@ CanonicalTopo canonicalizeTopo(const std::vector>& topo_lis bool isSameStat(const irt::TBRefineStat& first, const irt::TBRefineStat& second) { - return first.shifted_edge_num == second.shifted_edge_num && first.refined_steiner_num == second.refined_steiner_num - && first.attempted_congestion_flute == second.attempted_congestion_flute && first.used_congestion_flute == second.used_congestion_flute - && first.attempted_steiner_refine == second.attempted_steiner_refine && first.used_steiner_refine == second.used_steiner_refine - && first.used_terminal_mst == second.used_terminal_mst; + return first.shifted_edge_num == second.shifted_edge_num && first.used_terminal_mst == second.used_terminal_mst; } bool isTopoValid(const std::vector& terminal_list, const std::vector>& topo_list, const PlanarRect& region) @@ -487,7 +484,7 @@ bool checkBaseline() irt::TBRefineStat stat; std::vector> topo_list = RTTB.getPlanarTopoList(makeTask(getBaseTerminalList(), getWireCostQuery()), stat); passed = check(isSameTopo(topo_list, getBaseFluteTopoList()), "uniform finite cost keeps FLUTE topology") && passed; - passed = check(stat.shifted_edge_num == 0 && stat.refined_steiner_num == 0, "uniform cost does not refine topology") && passed; + passed = check(stat.shifted_edge_num == 0, "uniform cost does not shift topology") && passed; return passed; } @@ -512,7 +509,27 @@ bool checkCostDrivenShift() return passed; } -bool checkCongestionFluteGuard() +bool checkShiftEdgeFilter() +{ + irt::TBSegmentCostQuery query = [](const PlanarCoord& first, const PlanarCoord& second) { + double cost = getDistance(first, second); + if (first.get_x() == second.get_x() && first.get_x() == 30) { + cost += 100 * getDistance(first, second); + } + return cost; + }; + irt::TBTask task = makeTask(getBaseTerminalList(), query); + task.set_shift_edge_filter([](const PlanarCoord&, const PlanarCoord&) { return false; }); + irt::TBRefineStat stat; + std::vector> filtered_topo = RTTB.getPlanarTopoList(task, stat); + + bool passed = true; + passed = check(stat.shifted_edge_num == 0, "shift edge filter skips cool Steiner edges") && passed; + passed = check(isSameTopo(filtered_topo, getBaseFluteTopoList()), "filtered topology keeps the raw FLUTE tree") && passed; + return passed; +} + +bool checkCongestionRefineGuard() { irt::TBRefineStat low_degree_stat; std::vector> low_degree_topo @@ -522,17 +539,18 @@ bool checkCongestionFluteGuard() std::vector> uniform_topo = RTTB.getPlanarTopoList(makeTask(getBaseTerminalList(), getWireCostQuery(), true), uniform_stat); bool passed = true; - passed = check(!low_degree_topo.empty() && !low_degree_stat.attempted_congestion_flute, "two-pin net skips congestion FLUTE") && passed; - passed = check(uniform_stat.attempted_congestion_flute && !uniform_stat.used_congestion_flute, "uniform cost rejects equal congestion FLUTE candidate") + passed = check(!low_degree_topo.empty() && low_degree_stat.shifted_edge_num == 0 && !low_degree_stat.used_terminal_mst, + "two-pin net skips congestion refinement") && passed; - passed = check(isSameTopo(uniform_topo, getBaseFluteTopoList()), "uniform congestion FLUTE keeps baseline topology") && passed; + passed = check(uniform_stat.shifted_edge_num == 0 && !uniform_stat.used_terminal_mst, "uniform cost keeps the raw FLUTE candidate") && passed; + passed = check(isSameTopo(uniform_topo, getBaseFluteTopoList()), "uniform congestion refinement keeps baseline topology") && passed; for (const PlanarCoord& terminal : getBaseTerminalList()) { - passed = check(containsCoord(uniform_topo, terminal), "congestion FLUTE keeps terminal coordinate") && passed; + passed = check(containsCoord(uniform_topo, terminal), "congestion refinement keeps terminal coordinate") && passed; } return passed; } -bool checkCongestionFluteCostGuard() +bool checkCongestionUsesRawFluteOnly() { irt::TBSegmentCostQuery query = [](const PlanarCoord& first, const PlanarCoord& second) { double cost = getDistance(first, second); @@ -541,19 +559,19 @@ bool checkCongestionFluteCostGuard() } return cost; }; - std::vector> normal = RTTB.getPlanarTopoList(makeTask(getBaseTerminalList(), query)); + irt::TBRefineStat cost_stat; + std::vector> cost_topo = RTTB.getPlanarTopoList(makeTask(getBaseTerminalList(), query), cost_stat); irt::TBRefineStat stat; - std::vector> congestion = RTTB.getPlanarTopoList(makeTask(getBaseTerminalList(), query, true), stat); + std::vector> congestion_topo = RTTB.getPlanarTopoList(makeTask(getBaseTerminalList(), query, true), stat); bool passed = true; - passed = check(stat.attempted_congestion_flute, "costed four-pin net attempts congestion FLUTE") && passed; - passed = check(stat.used_congestion_flute, "lower-cost congestion FLUTE candidate is selected") && passed; - passed = check(getTopoCost(congestion, query) < getTopoCost(normal, query), "selected congestion FLUTE lowers topology cost") && passed; - passed = check(isSameTopo(congestion, RTTB.getPlanarTopoList(makeTask(getBaseTerminalList(), query, true))), "congestion FLUTE is deterministic") && passed; + passed = check(canonicalizeTopo(congestion_topo) == canonicalizeTopo(cost_topo), "congestion mode does not generate a second FLUTE tree") && passed; + passed = check(isSameStat(stat, cost_stat), "congestion mode uses the same raw FLUTE refinement") && passed; + passed = check(isTopoValid(getBaseTerminalList(), congestion_topo, PlanarRect(0, 0, 49, 49)), "raw congestion topology is valid") && passed; return passed; } -bool checkCongestionFluteQueryBound() +bool checkCostQueryBoundWithoutWarping() { int64_t query_num = 0; irt::TBSegmentCostQuery query = [&query_num](const PlanarCoord& first, const PlanarCoord& second) { @@ -562,7 +580,34 @@ bool checkCongestionFluteQueryBound() }; std::vector terminal_list = {PlanarCoord(0, 0), PlanarCoord(0, 200), PlanarCoord(200, 0), PlanarCoord(200, 200)}; RTTB.getPlanarTopoList(makeTask(terminal_list, query, true)); - return check(query_num <= 30000, "congestion FLUTE bounds bbox cost queries"); + return check(query_num <= 1000, "raw topology refinement bounds cost queries without axis-gap scanning: " + std::to_string(query_num)); +} + +bool checkThreePinCostQueryBound() +{ + int64_t query_num = 0; + irt::TBSegmentCostQuery query = [&query_num](const PlanarCoord& first, const PlanarCoord& second) { + query_num++; + return static_cast(getDistance(first, second)); + }; + RTTB.getPlanarTopoList(makeTask({PlanarCoord(0, 0), PlanarCoord(20, 40), PlanarCoord(40, 0)}, query, true)); + return check(query_num <= 1000, "three-pin raw topology refinement bounds cost queries: " + std::to_string(query_num)); +} + +bool checkThreePinCollinearRawFlute() +{ + const PlanarRect region(0, 0, 49, 49); + std::vector terminal_list = {PlanarCoord(5, 5), PlanarCoord(5, 20), PlanarCoord(5, 35)}; + irt::TBRefineStat stat; + std::vector> topo_list = RTTB.getPlanarTopoList(makeTask(terminal_list, getWireCostQuery(), true), stat); + std::vector> repeated_topo = RTTB.getPlanarTopoList(makeTask(terminal_list, getWireCostQuery(), true)); + + bool passed = true; + passed = check(stat.shifted_edge_num == 0 && !stat.used_terminal_mst, "collinear three-pin net keeps the raw FLUTE candidate") && passed; + passed = check(std::isfinite(getTopoCost(topo_list, getWireCostQuery())), "collinear three-pin topology has finite cost") && passed; + passed = check(isTopoValid(terminal_list, topo_list, region), "collinear three-pin topology is valid") && passed; + passed = check(canonicalizeTopo(topo_list) == canonicalizeTopo(repeated_topo), "collinear three-pin topology is deterministic") && passed; + return passed; } bool checkTwoPinFastPath() @@ -642,7 +687,7 @@ GridCostMap getBlockedMacroCostMap(const PlanarRect& macro) return getMacroRingCostMap(macro, 0, 1); } -bool checkCongestionFluteInfHandling() +bool checkCongestionInfHandling() { std::vector terminal_list = getBaseTerminalList(); irt::TBRefineStat partial_stat; @@ -654,12 +699,10 @@ bool checkCongestionFluteInfHandling() std::vector> fully_blocked_topo = RTTB.getPlanarTopoList(makeTask(terminal_list, fully_blocked_query, true), fully_blocked_stat); bool passed = true; - passed = check(partial_stat.attempted_congestion_flute, "partial INF still attempts congestion FLUTE") && passed; + passed = check(!partial_stat.used_terminal_mst, "partial INF is resolved without terminal MST") && passed; for (const PlanarCoord& terminal : terminal_list) { - passed = check(containsCoord(partial_topo, terminal), "partial INF congestion FLUTE keeps terminal") && passed; + passed = check(containsCoord(partial_topo, terminal), "partial INF refinement keeps terminal") && passed; } - passed = check(fully_blocked_stat.attempted_congestion_flute && !fully_blocked_stat.used_congestion_flute, "fully blocked bbox rejects congestion FLUTE") - && passed; passed = check(fully_blocked_stat.used_terminal_mst, "fully blocked bbox uses terminal MST fallback") && passed; passed = check(fully_blocked_topo.size() == terminal_list.size() - 1, "fully blocked fallback builds a tree") && passed; for (const Segment& segment : fully_blocked_topo) { @@ -689,11 +732,8 @@ bool checkThreePinCongestionAvoidsMacro() "full-layer macro excludes all terminals") && passed; passed = check(!std::isfinite(getTopoCost(raw_topo, query)), "full-layer macro blocks normal FLUTE topology") && passed; - passed = check(stat.attempted_congestion_flute && (stat.used_congestion_flute || stat.shifted_edge_num > 0), - "three-pin congestion topology is cost-driven") - && passed; - passed = check(!stat.attempted_steiner_refine && !stat.used_terminal_mst, "three-pin congestion topology avoids fallback") - && passed; + passed = check(stat.shifted_edge_num > 0, "three-pin congestion topology shifts a Steiner edge") && passed; + passed = check(!stat.used_terminal_mst, "three-pin congestion topology avoids fallback") && passed; passed = check(std::isfinite(getTopoCost(topo_list, query)), "three-pin congestion topology has finite cost") && passed; passed = check(!containsCoord(topo_list, raw_steiner), "three-pin congestion topology leaves blocked coordinate") && passed; passed = check(std::ranges::none_of(getSteinerCoordList(terminal_list, topo_list), [&](const PlanarCoord& steiner) { return isInsideRect(macro, steiner); }), @@ -726,13 +766,16 @@ bool checkThreePinCongestionOutsidePinBBox() std::vector steiner_list = getSteinerCoordList(terminal_list, topo_list); bool passed = true; - passed = check(stat.attempted_congestion_flute && stat.used_congestion_flute, "three-pin congestion searches outside pin bbox") && passed; - passed = check(!stat.attempted_steiner_refine && !stat.used_terminal_mst, "outside-bbox three-pin congestion avoids fallback") && passed; - passed = check(std::isfinite(getTopoCost(topo_list, query)), "outside-bbox three-pin topology has finite cost") && passed; - passed = check(std::ranges::any_of(steiner_list, [](const PlanarCoord& steiner) { return steiner.get_y() < 10; }), - "three-pin congestion places Steiner outside pin bbox") - && passed; - passed = check(isTopoValid(terminal_list, topo_list, region), "outside-bbox three-pin topology is valid") && passed; + passed = check(stat.used_terminal_mst, "outside-bbox three-pin congestion uses terminal MST fallback") && passed; + passed = check(!std::isfinite(getTopoCost(topo_list, query)), "fallback reports an unreachable outside-bbox corridor") && passed; + passed = check(steiner_list.empty(), "three-pin congestion does not enumerate Steiner points outside pin bbox") && passed; + passed = check(topo_list.size() == terminal_list.size() - 1, "outside-bbox fallback builds a terminal tree") && passed; + for (const Segment& segment : topo_list) { + passed = check(std::ranges::find(terminal_list, segment.get_first()) != terminal_list.end() + && std::ranges::find(terminal_list, segment.get_second()) != terminal_list.end(), + "outside-bbox fallback only uses terminals") + && passed; + } return passed; } @@ -743,8 +786,7 @@ bool checkGeometryDefersBlockedSteiner() irt::TBRefineStat stat; std::vector> topo_list = RTTB.getPlanarTopoList(makeGeometryTask(terminal_list, getBlockedMacroCostMap(macro).getQuery()), stat); bool passed = true; - passed = check(stat.shifted_edge_num == 0 && !stat.attempted_steiner_refine && !stat.used_terminal_mst, - "geometry mode skips cost refinement") + passed = check(stat.shifted_edge_num == 0 && !stat.used_terminal_mst, "geometry mode skips cost refinement") && passed; passed = check(containsCoord(topo_list, PlanarCoord(10, 0)), "geometry mode preserves raw Steiner") && passed; passed = check(!std::isfinite(getTopoCost(topo_list, getBlockedMacroCostMap(macro).getQuery())), @@ -765,7 +807,6 @@ bool checkMultiHotspotCompetition() std::vector> repeated_topo = RTTB.getPlanarTopoList(makeTask(terminal_list, query, true), repeated_stat); bool passed = true; - passed = check(stat.attempted_congestion_flute, "multi-hotspot attempts congestion FLUTE") && passed; passed = check(getTopoCost(congestion_topo, query) <= getTopoCost(normal_topo, query), "multi-hotspot topology does not increase cost") && passed; passed = check(isTopoValid(terminal_list, congestion_topo, region), "multi-hotspot topology is valid") && passed; passed = check(canonicalizeTopo(congestion_topo) == canonicalizeTopo(repeated_topo), "multi-hotspot topology is deterministic") && passed; @@ -784,7 +825,6 @@ bool checkFiniteCorridor() std::vector> repeated_topo = RTTB.getPlanarTopoList(makeTask(terminal_list, query, true)); bool passed = true; - passed = check(stat.attempted_congestion_flute, "finite corridor attempts congestion FLUTE") && passed; passed = check(std::isfinite(getTopoCost(selected_topo, query)), "finite corridor produces finite topology cost") && passed; passed = check(getTopoCost(selected_topo, query) <= getTopoCost(normal_topo, query), "finite corridor does not regress topology cost") && passed; passed = check(isTopoValid(terminal_list, selected_topo, region), "finite corridor topology is valid") && passed; @@ -792,7 +832,7 @@ bool checkFiniteCorridor() return passed; } -bool checkHighDegreeSteinerRefine() +bool checkHighDegreeWithoutPointRefine() { const PlanarRect region(0, 0, 49, 49); std::vector terminal_list @@ -806,20 +846,15 @@ bool checkHighDegreeSteinerRefine() return query(first, second); }; irt::TBRefineStat stat; - std::vector> refined_topo = RTTB.getPlanarTopoList(makeTask(terminal_list, counted_query, true), stat); + std::vector> selected_topo = RTTB.getPlanarTopoList(makeTask(terminal_list, counted_query, true), stat); + std::vector> repeated_topo = RTTB.getPlanarTopoList(makeTask(terminal_list, query, true)); bool passed = true; passed = check(raw_steiner_list.size() >= 2, "high-degree case has multiple raw Steiner coordinates") && passed; - passed - = check(stat.attempted_steiner_refine && stat.used_steiner_refine && stat.refined_steiner_num > 0, "high-degree blocked topology uses Steiner refinement") - && passed; - passed = check(!stat.used_terminal_mst, "finite high-degree refinement avoids terminal MST") && passed; - for (const PlanarCoord& raw_steiner : raw_steiner_list) { - passed = check(!containsCoord(refined_topo, raw_steiner), "high-degree refinement leaves blocked Steiner coordinate") && passed; - } - passed = check(std::isfinite(getTopoCost(refined_topo, query)), "high-degree refinement produces finite topology") && passed; - passed = check(isTopoValid(terminal_list, refined_topo, region), "high-degree refined topology is valid") && passed; - passed = check(query_num <= 50000, "high-degree refinement bounds cost queries") && passed; + passed = check(std::isfinite(getTopoCost(selected_topo, query)), "high-degree blocked topology remains routable") && passed; + passed = check(isTopoValid(terminal_list, selected_topo, region), "high-degree blocked topology is valid") && passed; + passed = check(canonicalizeTopo(selected_topo) == canonicalizeTopo(repeated_topo), "high-degree blocked topology is deterministic") && passed; + passed = check(query_num <= 50000, "high-degree blocked topology bounds cost queries") && passed; return passed; } @@ -839,7 +874,6 @@ bool checkHighDegreeStress() std::vector> repeated_topo = RTTB.getPlanarTopoList(makeTask(terminal_list, base_query, true), repeated_stat); bool passed = true; - passed = check(stat.attempted_congestion_flute, "high-degree net attempts congestion FLUTE") && passed; passed = check(std::isfinite(getTopoCost(topo_list, base_query)), "high-degree topology has finite cost") && passed; passed = check(isTopoValid(terminal_list, topo_list, region), "high-degree topology is valid") && passed; passed = check(canonicalizeTopo(topo_list) == canonicalizeTopo(repeated_topo), "high-degree topology is deterministic") && passed; @@ -870,8 +904,7 @@ bool checkPartialLayerMacroKeepsSteiner() } passed = check(canonicalizeTopo(selected_topo) == canonicalizeTopo(baseline_topo), "partial-layer macro keeps FLUTE topology") && passed; passed = check(containsCoord(selected_topo, steiner), "partial-layer macro keeps Steiner coordinate") && passed; - passed - = check(stat.shifted_edge_num == 0 && stat.refined_steiner_num == 0 && !stat.used_terminal_mst, "partial-layer macro does not refine Steiner") && passed; + passed = check(stat.shifted_edge_num == 0 && !stat.used_terminal_mst, "partial-layer macro does not shift Steiner") && passed; passed = check(std::isfinite(getTopoCost(selected_topo, query)), "partial-layer macro topology has finite cost") && passed; passed = check(isTopoValid(terminal_list, selected_topo, region), "partial-layer macro topology is valid") && passed; return passed; @@ -900,9 +933,8 @@ bool checkFullLayerMacroCongestionRing() passed = check(query(PlanarCoord(16, 18), PlanarCoord(17, 18)) == 50, "macro congestion ring has high finite cost") && passed; passed = check(query(PlanarCoord(0, 0), PlanarCoord(1, 0)) == 1, "edges outside macro ring keep base cost") && passed; passed = check(!std::isfinite(getTopoCost(raw_topo, query)), "full-layer macro blocks raw FLUTE topology") && passed; - passed = check(stat.attempted_congestion_flute, "full-layer macro ring attempts congestion FLUTE") && passed; - passed = check(stat.used_congestion_flute || stat.shifted_edge_num > 0, "full-layer macro ring selects a cost-driven topology") && passed; - passed = check(!stat.attempted_steiner_refine && !stat.used_terminal_mst, "full-layer macro ring avoids fallback") && passed; + passed = check(stat.shifted_edge_num > 0, "full-layer macro ring shifts a Steiner edge") && passed; + passed = check(!stat.used_terminal_mst, "full-layer macro ring avoids fallback") && passed; passed = check(std::isfinite(getTopoCost(selected_topo, query)), "full-layer macro ring topology has finite cost") && passed; passed = check(canonicalizeTopo(selected_topo) != canonicalizeTopo(raw_topo), "full-layer macro ring changes raw topology") && passed; passed = check(std::isfinite(getTopoCost(selected_topo, strict_avoid_query)), "selected topology can avoid macro congestion ring") && passed; @@ -1301,15 +1333,15 @@ bool generatePlots(const std::filesystem::path& plot_dir) } return cost; }; - std::vector> normal = RTTB.getPlanarTopoList(makeTask(base_terminal_list, congestion_query)); + std::vector> normal = RTTB.getPlanarTopoList(makeGeometryTask(base_terminal_list)); irt::TBRefineStat congestion_stat; std::vector> congestion = RTTB.getPlanarTopoList(makeTask(base_terminal_list, congestion_query, true), congestion_stat); - plot_case_list.push_back({.file_name = "03_congestion_flute.svg", - .title = "Normal vs congestion FLUTE", + plot_case_list.push_back({.file_name = "03_congestion_refine.svg", + .title = "Raw FLUTE vs congestion refinement", .summary = "normal_cost=" + formatCost(getTopoCost(normal, congestion_query)) + ", congestion_cost=" + formatCost(getTopoCost(congestion, congestion_query)) - + ", attempted=" + std::to_string(congestion_stat.attempted_congestion_flute) - + ", used=" + std::to_string(congestion_stat.used_congestion_flute), + + ", shifted=" + std::to_string(congestion_stat.shifted_edge_num) + + ", mst=" + std::to_string(congestion_stat.used_terminal_mst), .region = region, .terminal_list = base_terminal_list, .topo_layer_list = {{"normal", normal, "#6b7280", true}, {"congestion", congestion, "#16a34a", false}}, @@ -1324,7 +1356,8 @@ bool generatePlots(const std::filesystem::path& plot_dir) .title = "INF edge handling", .summary = "normal_cost=" + formatCost(getTopoCost(blocked_normal, blocked_query)) + ", selected_cost=" + formatCost(getTopoCost(blocked_congestion, blocked_query)) - + ", congestion_used=" + std::to_string(blocked_stat.used_congestion_flute), + + ", shifted=" + std::to_string(blocked_stat.shifted_edge_num) + + ", mst=" + std::to_string(blocked_stat.used_terminal_mst), .region = region, .terminal_list = base_terminal_list, .topo_layer_list = {{"normal", blocked_normal, "#6b7280", true}, {"selected", blocked_congestion, "#16a34a", false}}, @@ -1340,9 +1373,9 @@ bool generatePlots(const std::filesystem::path& plot_dir) std::vector> congestion_topo = RTTB.getPlanarTopoList(makeTask(three_pin_terminal_list, three_pin_query, true), three_pin_stat); plot_case_list.push_back( {.file_name = "05_three_pin_congestion.svg", - .title = "Three-pin congestion FLUTE", - .summary = "attempted=" + std::to_string(three_pin_stat.attempted_congestion_flute) + ", used=" + std::to_string(three_pin_stat.used_congestion_flute) - + ", cost=" + formatCost(getTopoCost(congestion_topo, three_pin_query)) + ", mst=" + std::to_string(three_pin_stat.used_terminal_mst), + .title = "Three-pin congestion refinement", + .summary = "shifted=" + std::to_string(three_pin_stat.shifted_edge_num) + ", cost=" + formatCost(getTopoCost(congestion_topo, three_pin_query)) + + ", mst=" + std::to_string(three_pin_stat.used_terminal_mst), .region = PlanarRect(0, 0, 24, 24), .terminal_list = three_pin_terminal_list, .macro_rect_list = {three_pin_macro}, @@ -1360,7 +1393,8 @@ bool generatePlots(const std::filesystem::path& plot_dir) .title = "Multi-hotspot topology competition", .summary = "normal_cost=" + formatCost(getTopoCost(hotspot_normal, hotspot_query)) + ", selected_cost=" + formatCost(getTopoCost(hotspot_congestion, hotspot_query)) - + ", congestion_used=" + std::to_string(hotspot_stat.used_congestion_flute), + + ", shifted=" + std::to_string(hotspot_stat.shifted_edge_num) + + ", mst=" + std::to_string(hotspot_stat.used_terminal_mst), .region = region, .terminal_list = hotspot_terminal_list, .topo_layer_list = {{"normal", hotspot_normal, "#6b7280", true}, {"congestion", hotspot_congestion, "#16a34a", false}}, @@ -1375,33 +1409,36 @@ bool generatePlots(const std::filesystem::path& plot_dir) .title = "Finite corridors through INF field", .summary = "normal_cost=" + formatCost(getTopoCost(corridor_normal, corridor_query)) + ", selected_cost=" + formatCost(getTopoCost(corridor_selected, corridor_query)) - + ", congestion_used=" + std::to_string(corridor_stat.used_congestion_flute), + + ", shifted=" + std::to_string(corridor_stat.shifted_edge_num) + + ", mst=" + std::to_string(corridor_stat.used_terminal_mst), .region = region, .terminal_list = corridor_terminal_list, .topo_layer_list = {{"normal", corridor_normal, "#6b7280", true}, {"selected", corridor_selected, "#16a34a", false}}, .cost_query = corridor_query}); - std::vector refine_terminal_list + std::vector blocked_terminal_list = {PlanarCoord(0, 0), PlanarCoord(0, 40), PlanarCoord(10, 15), PlanarCoord(25, 30), PlanarCoord(40, 0), PlanarCoord(40, 40)}; - std::vector> refine_raw = RTTB.getPlanarTopoList(makeTask(refine_terminal_list)); - std::vector multi_raw_steiner_list = getSteinerCoordList(refine_terminal_list, refine_raw); - irt::TBSegmentCostQuery refine_query = getSteinerBlockedCostMap(multi_raw_steiner_list).getQuery(); - irt::TBRefineStat refine_stat; - std::vector> refined_topo = RTTB.getPlanarTopoList(makeTask(refine_terminal_list, refine_query, true), refine_stat); - std::vector refine_marker_list; + std::vector> blocked_raw = RTTB.getPlanarTopoList(makeTask(blocked_terminal_list)); + std::vector multi_raw_steiner_list = getSteinerCoordList(blocked_terminal_list, blocked_raw); + irt::TBSegmentCostQuery steiner_blocked_query = getSteinerBlockedCostMap(multi_raw_steiner_list).getQuery(); + irt::TBRefineStat steiner_blocked_stat; + std::vector> blocked_topo + = RTTB.getPlanarTopoList(makeTask(blocked_terminal_list, steiner_blocked_query, true), steiner_blocked_stat); + std::vector blocked_marker_list; for (const PlanarCoord& steiner : multi_raw_steiner_list) { - refine_marker_list.push_back({steiner, "blocked Steiner", "#dc2626"}); + blocked_marker_list.push_back({steiner, "blocked Steiner", "#dc2626"}); } plot_case_list.push_back( - {.file_name = "08_high_degree_refine.svg", - .title = "High-degree Steiner refinement", - .summary = "attempted=" + std::to_string(refine_stat.attempted_steiner_refine) + ", used=" + std::to_string(refine_stat.used_steiner_refine) - + ", refined=" + std::to_string(refine_stat.refined_steiner_num) + ", cost=" + formatCost(getTopoCost(refined_topo, refine_query)), + {.file_name = "08_high_degree_blocked.svg", + .title = "High-degree blocked Steiner handling", + .summary = "shifted=" + std::to_string(steiner_blocked_stat.shifted_edge_num) + + ", mst=" + std::to_string(steiner_blocked_stat.used_terminal_mst) + + ", cost=" + formatCost(getTopoCost(blocked_topo, steiner_blocked_query)), .region = region, - .terminal_list = refine_terminal_list, - .topo_layer_list = {{"raw", refine_raw, "#6b7280", true}, {"refined", refined_topo, "#2563eb", false}}, - .marker_list = std::move(refine_marker_list), - .cost_query = refine_query}); + .terminal_list = blocked_terminal_list, + .topo_layer_list = {{"raw", blocked_raw, "#6b7280", true}, {"selected", blocked_topo, "#2563eb", false}}, + .marker_list = std::move(blocked_marker_list), + .cost_query = steiner_blocked_query}); std::vector stress_terminal_list = getHighDegreeTerminalList(); irt::TBSegmentCostQuery stress_query = getHighDegreeCostMap().getQuery(); @@ -1412,7 +1449,7 @@ bool generatePlots(const std::filesystem::path& plot_dir) {.file_name = "09_high_degree_stress.svg", .title = "High-degree deterministic stress", .summary = "pins=" + std::to_string(stress_terminal_list.size()) + ", cost=" + formatCost(getTopoCost(stress_congestion, stress_query)) - + ", shifted=" + std::to_string(stress_stat.shifted_edge_num) + ", congestion_used=" + std::to_string(stress_stat.used_congestion_flute), + + ", shifted=" + std::to_string(stress_stat.shifted_edge_num) + ", mst=" + std::to_string(stress_stat.used_terminal_mst), .region = region, .terminal_list = stress_terminal_list, .topo_layer_list = {{"normal", stress_normal, "#6b7280", true}, {"selected", stress_congestion, "#7c3aed", false}}, @@ -1426,8 +1463,7 @@ bool generatePlots(const std::filesystem::path& plot_dir) plot_case_list.push_back({.file_name = "10_partial_layer_macro.svg", .title = "Partial-layer macro keeps Steiner", .summary = "steiner=(" + std::to_string(macro_steiner.get_x()) + "," + std::to_string(macro_steiner.get_y()) - + "), finite_escape=1, shifted=" + std::to_string(partial_macro_stat.shifted_edge_num) - + ", refined=" + std::to_string(partial_macro_stat.refined_steiner_num), + + "), finite_escape=1, shifted=" + std::to_string(partial_macro_stat.shifted_edge_num), .region = region, .terminal_list = base_terminal_list, .macro_rect_list = {partial_macro}, @@ -1443,9 +1479,8 @@ bool generatePlots(const std::filesystem::path& plot_dir) plot_case_list.push_back( {.file_name = "11_full_layer_macro_ring.svg", .title = "Full-layer macro with congestion ring", - .summary = "attempted=" + std::to_string(macro_ring_stat.attempted_congestion_flute) + ", used=" + std::to_string(macro_ring_stat.used_congestion_flute) - + ", shifted=" + std::to_string(macro_ring_stat.shifted_edge_num) + ", cost=" + formatCost(getTopoCost(macro_ring_topo, macro_ring_query)) - + ", refined=" + std::to_string(macro_ring_stat.refined_steiner_num), + .summary = "shifted=" + std::to_string(macro_ring_stat.shifted_edge_num) + ", mst=" + std::to_string(macro_ring_stat.used_terminal_mst) + + ", cost=" + formatCost(getTopoCost(macro_ring_topo, macro_ring_query)), .region = region, .terminal_list = base_terminal_list, .macro_rect_list = {full_layer_macro}, @@ -1488,17 +1523,20 @@ int main(int argc, char* argv[]) bool passed = true; passed = checkBaseline() && passed; passed = checkCostDrivenShift() && passed; - passed = checkCongestionFluteGuard() && passed; - passed = checkCongestionFluteCostGuard() && passed; - passed = checkCongestionFluteQueryBound() && passed; + passed = checkShiftEdgeFilter() && passed; + passed = checkCongestionRefineGuard() && passed; + passed = checkCongestionUsesRawFluteOnly() && passed; + passed = checkCostQueryBoundWithoutWarping() && passed; + passed = checkThreePinCostQueryBound() && passed; + passed = checkThreePinCollinearRawFlute() && passed; passed = checkTwoPinFastPath() && passed; - passed = checkCongestionFluteInfHandling() && passed; + passed = checkCongestionInfHandling() && passed; passed = checkThreePinCongestionAvoidsMacro() && passed; passed = checkThreePinCongestionOutsidePinBBox() && passed; passed = checkGeometryDefersBlockedSteiner() && passed; passed = checkMultiHotspotCompetition() && passed; passed = checkFiniteCorridor() && passed; - passed = checkHighDegreeSteinerRefine() && passed; + passed = checkHighDegreeWithoutPointRefine() && passed; passed = checkHighDegreeStress() && passed; passed = checkPartialLayerMacroKeepsSteiner() && passed; passed = checkFullLayerMacroCongestionRing() && passed;