From 2e3ebc3f47608b140c06ae899fee05e27d1af674 Mon Sep 17 00:00:00 2001 From: SuanQ1212 <572942506@qq.com> Date: Wed, 9 Sep 2026 11:19:38 +0800 Subject: [PATCH 1/5] iRT topo_builder update,runtime opa+ --- .../module/planar_router/PlanarRouter.cpp | 76 +- .../module/planar_router/PlanarRouter.hpp | 2 +- .../module/topo_builder/TOPOBuilder.cpp | 718 ++++-------------- .../module/topo_builder/TOPOBuilder.hpp | 5 - .../topo_builder/tb_data_manager/TBTask.hpp | 5 + .../test_topo_builder/test_topo_builder.cpp | 230 +++--- 6 files changed, 372 insertions(+), 664 deletions(-) diff --git a/src/operation/iRT/source/module/planar_router/PlanarRouter.cpp b/src/operation/iRT/source/module/planar_router/PlanarRouter.cpp index 739e4af01a..b74d36f8fb 100644 --- a/src/operation/iRT/source/module/planar_router/PlanarRouter.cpp +++ b/src/operation/iRT/source/module/planar_router/PlanarRouter.cpp @@ -28,6 +28,9 @@ namespace irt { namespace { +constexpr double kSteinerShiftUsageThreshold = 0.8; +constexpr double kSteinerShiftHistoryRatio = 0.64; + struct PRSegmentKey { int32_t ll_x; @@ -876,7 +879,7 @@ std::vector PlanarRouter::getPRCandidateListByTopo(PRModel& pr_mode return pr_candidate_list; } -bool PlanarRouter::shouldUseCongestionFlute(PRModel& pr_model, size_t unique_pin_num) +bool PlanarRouter::shouldRefineTopology(PRModel& pr_model, size_t unique_pin_num) { if (unique_pin_num < 3) { return false; @@ -885,13 +888,14 @@ bool PlanarRouter::shouldUseCongestionFlute(PRModel& pr_model, size_t unique_pin if (curr_net->get_routing_edge_set().empty()) { return true; } - double history_threshold = 0.64 * pr_model.get_pr_com_param().get_overflow_unit(); + double history_threshold = kSteinerShiftHistoryRatio * pr_model.get_pr_com_param().get_overflow_unit(); for (RoutingEdge* routing_edge : curr_net->get_routing_edge_set()) { if (routing_edge->get_ignore_net_set().contains(curr_net->get_net_idx())) { continue; } int32_t supply = routing_edge->get_supply(); - if (supply <= 0 || routing_edge->get_demand() / static_cast(supply) >= 0.8 || routing_edge->get_congestion_cost() >= history_threshold) { + if (supply <= 0 || routing_edge->get_demand() / static_cast(supply) >= kSteinerShiftUsageThreshold + || routing_edge->get_congestion_cost() >= history_threshold) { return true; } } @@ -912,9 +916,9 @@ std::vector> PlanarRouter::getPlanarTopoList(PRModel& pr_mo 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(pr_model, 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(pr_model, planar_coord_list.size()); + tb_task.set_topo_mode(refine_topology ? TBTopoMode::kCongestion : TBTopoMode::kGeometry); + if (!refine_topology) { return RTTB.getPlanarTopoList(tb_task); } @@ -923,6 +927,66 @@ std::vector> PlanarRouter::getPlanarTopoList(PRModel& pr_mo PRTopologyCostCache topology_cost_cache(std::move(segment_cost_query)); tb_task.set_segment_cost_query( [&topology_cost_cache](const PlanarCoord& first, const PlanarCoord& second) { return topology_cost_cache.getCost(first, second); }); + + GridMap& routing_h_edge_map = RTDM.getDatabase().get_planar_routing_h_edge_map(); + GridMap& routing_v_edge_map = RTDM.getDatabase().get_planar_routing_v_edge_map(); + PRNet* curr_net = pr_model.get_curr_pr_task(); + int32_t net_idx = curr_net->get_net_idx(); + double overflow_unit = pr_model.get_pr_com_param().get_overflow_unit(); + const std::unordered_set& routing_edge_set = curr_net->get_routing_edge_set(); + std::unordered_map shift_hot_cache; + shift_hot_cache.reserve(64); + auto is_hot_edge = [&routing_edge_set, net_idx, overflow_unit](RoutingEdge& edge) { + if (edge.get_ignore_net_set().contains(net_idx)) { + return false; + } + int32_t effective_demand = std::max(0, edge.get_demand() - routing_edge_set.contains(&edge)); + return edge.get_supply() <= 0 || effective_demand / static_cast(edge.get_supply()) >= kSteinerShiftUsageThreshold + || edge.get_congestion_cost() >= kSteinerShiftHistoryRatio * overflow_unit; + }; + auto is_hot_segment = [&routing_h_edge_map, &routing_v_edge_map, &shift_hot_cache, &is_hot_edge](const PlanarCoord& first, + const PlanarCoord& second) { + if (first == second || !RTUTIL.isRightAngled(first, second)) { + return false; + } + PRSegmentKey key{std::min(first.get_x(), second.get_x()), std::min(first.get_y(), second.get_y()), std::max(first.get_x(), second.get_x()), + std::max(first.get_y(), second.get_y())}; + if (auto iter = shift_hot_cache.find(key); iter != shift_hot_cache.end()) { + return iter->second; + } + bool is_hot = false; + if (RTUTIL.isHorizontal(first, second)) { + if (key.ll_x < 0 || key.ur_x > routing_h_edge_map.get_x_size() || key.ll_y < 0 || key.ll_y >= routing_h_edge_map.get_y_size()) { + return false; + } + for (int32_t x = key.ll_x; x < key.ur_x; x++) { + if (is_hot_edge(routing_h_edge_map[x][key.ll_y])) { + is_hot = true; + break; + } + } + } else { + if (key.ll_x < 0 || key.ll_x >= routing_v_edge_map.get_x_size() || key.ll_y < 0 || key.ur_y > routing_v_edge_map.get_y_size()) { + return false; + } + for (int32_t y = key.ll_y; y < key.ur_y; y++) { + if (is_hot_edge(routing_v_edge_map[key.ll_x][y])) { + is_hot = true; + break; + } + } + } + shift_hot_cache.emplace(key, is_hot); + return is_hot; + }; + tb_task.set_shift_edge_filter([&is_hot_segment](const PlanarCoord& first, const PlanarCoord& second) { + if (first.get_x() == second.get_x() || first.get_y() == second.get_y()) { + return is_hot_segment(first, second); + } + PlanarCoord x_bend(second.get_x(), first.get_y()); + PlanarCoord y_bend(first.get_x(), second.get_y()); + return is_hot_segment(first, x_bend) || is_hot_segment(x_bend, second) || is_hot_segment(first, y_bend) || is_hot_segment(y_bend, second); + }); 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 d41aa3d07e..4aac11195c 100644 --- a/src/operation/iRT/source/module/planar_router/PlanarRouter.hpp +++ b/src/operation/iRT/source/module/planar_router/PlanarRouter.hpp @@ -151,7 +151,7 @@ class PlanarRouter PROverflowTask getOverflowTask(PRModel& pr_model, int32_t rip_up_guard); bool isBetterCandidate(PRModel& pr_model, const PRCandidate& candidate, const PRCandidate& best_candidate); std::vector getPRCandidateListByTopo(PRModel& pr_model, Segment& planar_topo, PRRouteMode pr_route_mode); - bool shouldUseCongestionFlute(PRModel& pr_model, size_t unique_pin_num); + bool shouldRefineTopology(PRModel& pr_model, size_t unique_pin_num); std::vector> getPlanarTopoList(PRModel& pr_model, 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; From a4fb1264b97a6bf12ef10aee2e479f5cdaf2c2ae Mon Sep 17 00:00:00 2001 From: ZhishengZeng Date: Tue, 15 Sep 2026 10:58:43 +0800 Subject: [PATCH 2/5] refactor(iRT): remove obsolete timing update path --- src/feature/database/feature_irt.h | 5 - src/feature/parser/feature_parser_tools.cpp | 20 -- src/interface/python/py_irt/py_irt_utils.cpp | 4 +- src/interface/tcl/tcl_irt/src/tcl_init_rt.cpp | 2 - src/operation/iRT/interface/RTInterface.cpp | 223 ------------------ src/operation/iRT/interface/RTInterface.hpp | 6 - .../iRT/source/data_manager/DataManager.cpp | 2 - .../source/data_manager/advance/Config.hpp | 1 - .../source/data_manager/advance/Summary.hpp | 5 - .../module/detailed_router/DetailedRouter.cpp | 36 --- .../module/layer_assigner/LayerAssigner.cpp | 45 ---- .../module/planar_router/PlanarRouter.cpp | 44 ---- .../violation_reporter/ViolationReporter.cpp | 36 --- test/fixtures/gcd/config/route_ecc.json | 3 +- 14 files changed, 2 insertions(+), 430 deletions(-) diff --git a/src/feature/database/feature_irt.h b/src/feature/database/feature_irt.h index e60bb3a416..2c6df1b8e8 100644 --- a/src/feature/database/feature_irt.h +++ b/src/feature/database/feature_irt.h @@ -49,7 +49,6 @@ struct PRSummary double total_demand = 0; double total_overflow = 0; double total_wire_length = 0; - std::map> clock_timing_map; std::map type_power_map; }; @@ -63,7 +62,6 @@ struct LASummary double total_wire_length = 0; std::map cut_via_num_map; int32_t total_via_num = 0; - std::map> clock_timing_map; std::map type_power_map; }; @@ -77,7 +75,6 @@ struct SRSummary double total_wire_length = 0; std::map cut_via_num_map; int32_t total_via_num = 0; - std::map> clock_timing_map; std::map type_power_map; }; @@ -99,7 +96,6 @@ struct DRSummary int32_t total_patch_num = 0; std::map routing_violation_num_map; int32_t total_violation_num = 0; - std::map> clock_timing_map; std::map type_power_map; }; @@ -119,7 +115,6 @@ struct VRSummary std::map among_net_violation_type_num_map; std::map among_net_routing_violation_num_map; int32_t among_net_total_violation_num = 0; - std::map> clock_timing_map; std::map type_power_map; }; diff --git a/src/feature/parser/feature_parser_tools.cpp b/src/feature/parser/feature_parser_tools.cpp index b5f1a7ddde..bdd25036da 100644 --- a/src/feature/parser/feature_parser_tools.cpp +++ b/src/feature/parser/feature_parser_tools.cpp @@ -85,10 +85,6 @@ json FeatureParser::buildSummaryRT() pr_json["total_demand"] = summary_irt.pr_summary.total_demand; pr_json["total_overflow"] = summary_irt.pr_summary.total_overflow; pr_json["total_wire_length"] = summary_irt.pr_summary.total_wire_length; - for (auto& [clock_name, timing] : summary_irt.pr_summary.clock_timing_map) { - pr_json["clock_timing_map"]["clock_name"] = clock_name; - pr_json["clock_timing_map"]["timing"] = timing; - } for (auto& [type, power] : summary_irt.pr_summary.type_power_map) { pr_json["type_power_map"]["type"] = type; pr_json["type_power_map"]["power"] = power; @@ -115,10 +111,6 @@ json FeatureParser::buildSummaryRT() la_json["cut_via_num_map"][std::to_string(cut_layer_idx)] = via_num; } la_json["total_via_num"] = summary_irt.la_summary.total_via_num; - for (auto& [clock_name, timing] : summary_irt.la_summary.clock_timing_map) { - la_json["clock_timing_map"]["clock_name"] = clock_name; - la_json["clock_timing_map"]["timing"] = timing; - } for (auto& [type, power] : summary_irt.la_summary.type_power_map) { la_json["type_power_map"]["type"] = type; la_json["type_power_map"]["power"] = power; @@ -148,10 +140,6 @@ json FeatureParser::buildSummaryRT() sr_json["cut_via_num_map"][std::to_string(cut_layer_idx)] = via_num; } sr_json["total_via_num"] = sr_summary.total_via_num; - for (auto& [clock_name, timing] : sr_summary.clock_timing_map) { - sr_json["clock_timing_map"]["clock_name"] = clock_name; - sr_json["clock_timing_map"]["timing"] = timing; - } for (auto& [type, power] : sr_summary.type_power_map) { sr_json["type_power_map"]["type"] = type; sr_json["type_power_map"]["power"] = power; @@ -197,10 +185,6 @@ json FeatureParser::buildSummaryRT() dr_json["routing_violation_num_map"][std::to_string(routing_layer_idx)] = violation_num; } dr_json["total_violation_num"] = dr_summary.total_violation_num; - for (auto& [clock_name, timing] : dr_summary.clock_timing_map) { - dr_json["clock_timing_map"]["clock_name"] = clock_name; - dr_json["clock_timing_map"]["timing"] = timing; - } for (auto& [type, power] : dr_summary.type_power_map) { dr_json["type_power_map"]["type"] = type; dr_json["type_power_map"]["power"] = power; @@ -233,10 +217,6 @@ json FeatureParser::buildSummaryRT() vr_json["among_net_routing_violation_num_map"][std::to_string(routing_layer_idx)] = violation_num; } vr_json["among_net_total_violation_num"] = summary_irt.vr_summary.among_net_total_violation_num; - for (auto& [clock_name, timing] : summary_irt.vr_summary.clock_timing_map) { - vr_json["clock_timing_map"]["clock_name"] = clock_name; - vr_json["clock_timing_map"]["timing"] = timing; - } for (auto& [type, power] : summary_irt.vr_summary.type_power_map) { vr_json["type_power_map"]["type"] = type; vr_json["type_power_map"]["power"] = power; diff --git a/src/interface/python/py_irt/py_irt_utils.cpp b/src/interface/python/py_irt/py_irt_utils.cpp index f9952cb29e..86e52cb659 100644 --- a/src/interface/python/py_irt/py_irt_utils.cpp +++ b/src/interface/python/py_irt/py_irt_utils.cpp @@ -107,8 +107,6 @@ bool initConfigMapByJSON(const std::string& config, std::map& config_map) RTDM.getConfig().bottom_routing_layer = RTUTIL.getConfigValue(config_map, "-bottom_routing_layer", ""); RTDM.getConfig().top_routing_layer = RTUTIL.getConfigValue(config_map, "-top_routing_layer", ""); RTDM.getConfig().output_inter_result = RTUTIL.getConfigValue(config_map, "-output_inter_result", 0); - RTDM.getConfig().enable_timing = RTUTIL.getConfigValue(config_map, "-enable_timing", 0); ///////////////////////////////////////////// } @@ -1451,7 +1450,6 @@ void RTInterface::outputSummary() top_rt_summary.pr_summary.total_demand = rt_summary.pr_summary.total_demand; top_rt_summary.pr_summary.total_overflow = rt_summary.pr_summary.total_overflow; top_rt_summary.pr_summary.total_wire_length = rt_summary.pr_summary.total_wire_length; - top_rt_summary.pr_summary.clock_timing_map = rt_summary.pr_summary.clock_timing_map; } // la_summary { @@ -1463,7 +1461,6 @@ void RTInterface::outputSummary() top_rt_summary.la_summary.total_wire_length = rt_summary.la_summary.total_wire_length; top_rt_summary.la_summary.cut_via_num_map = rt_summary.la_summary.cut_via_num_map; top_rt_summary.la_summary.total_via_num = rt_summary.la_summary.total_via_num; - top_rt_summary.la_summary.clock_timing_map = rt_summary.la_summary.clock_timing_map; } // sr_summary { @@ -1477,7 +1474,6 @@ void RTInterface::outputSummary() top_sr_summary.total_wire_length = sr_summary.total_wire_length; top_sr_summary.cut_via_num_map = sr_summary.cut_via_num_map; top_sr_summary.total_via_num = sr_summary.total_via_num; - top_sr_summary.clock_timing_map = sr_summary.clock_timing_map; } } // ta_summary @@ -1499,7 +1495,6 @@ void RTInterface::outputSummary() top_dr_summary.total_patch_num = dr_summary.total_patch_num; top_dr_summary.routing_violation_num_map = dr_summary.routing_violation_num_map; top_dr_summary.total_violation_num = dr_summary.total_violation_num; - top_dr_summary.clock_timing_map = dr_summary.clock_timing_map; } } // vr_summary @@ -1518,7 +1513,6 @@ void RTInterface::outputSummary() top_rt_summary.vr_summary.among_net_violation_type_num_map = rt_summary.vr_summary.among_net_violation_type_num_map; top_rt_summary.vr_summary.among_net_routing_violation_num_map = rt_summary.vr_summary.among_net_routing_violation_num_map; top_rt_summary.vr_summary.among_net_total_violation_num = rt_summary.vr_summary.among_net_total_violation_num; - top_rt_summary.vr_summary.clock_timing_map = rt_summary.vr_summary.clock_timing_map; } } @@ -1718,223 +1712,6 @@ ids::Shape RTInterface::getIDSShape(int32_t net_idx, LayerRect layer_rect, bool #endif -#if 1 // iSTA - -void RTInterface::updateTiming(std::vector>>& real_pin_coord_map_list, - std::vector>>& routing_segment_list_list, - std::map>& clock_timing) -{ -#if 0 -#if 1 // 数据结构定义 - struct RCPin - { - RCPin() = default; - RCPin(LayerCoord coord, bool is_real_pin, std::string pin_name) - { - _coord = coord; - _is_real_pin = is_real_pin; - _pin_name = pin_name; - } - RCPin(LayerCoord coord, bool is_real_pin, int32_t fake_pin_id) - { - _coord = coord; - _is_real_pin = is_real_pin; - _fake_pin_id = fake_pin_id; - } - ~RCPin() = default; - - LayerCoord _coord; - bool _is_real_pin = false; - std::string _pin_name; - int32_t _fake_pin_id = -1; - }; -#endif - -#if 1 // 函数定义 - auto initTimingEngine = [](std::string workspace) { - ista::TimingEngine* timing_engine = ista::TimingEngine::getOrCreateTimingEngine(); - if (!timing_engine->isBuildGraph()) { - timing_engine->set_design_work_space(workspace.c_str()); - timing_engine->readLiberty(dmInst->get_config().get_lib_paths()); - auto db_adapter = std::make_unique(timing_engine->get_ista()); - db_adapter->set_idb(dmInst->get_idb_builder()); - db_adapter->convertDBToTimingNetlist(); - timing_engine->set_db_adapter(std::move(db_adapter)); - timing_engine->readSdc(dmInst->get_config().get_sdc_path().c_str()); - timing_engine->buildGraph(); - } - timing_engine->initRcTree(); - return timing_engine; - }; - auto getRCSegmentList - = [](std::map, CmpLayerCoordByXASC>& coord_real_pin_map, std::vector>& routing_segment_list) { - // 预处理 对名字去重 - for (auto& [coord, real_pin_list] : coord_real_pin_map) { - std::ranges::sort(real_pin_list); - real_pin_list.erase(std::ranges::unique(real_pin_list).begin(), real_pin_list.end()); - } - // 构建coord_fake_pin_map - std::map coord_fake_pin_map; - { - int32_t fake_id = 0; - for (Segment& routing_segment : routing_segment_list) { - LayerCoord& first_coord = routing_segment.get_first(); - LayerCoord& second_coord = routing_segment.get_second(); - - if (!RTUTIL.exist(coord_real_pin_map, first_coord) && !RTUTIL.exist(coord_fake_pin_map, first_coord)) { - coord_fake_pin_map[first_coord] = fake_id++; - } - if (!RTUTIL.exist(coord_real_pin_map, second_coord) && !RTUTIL.exist(coord_fake_pin_map, second_coord)) { - coord_fake_pin_map[second_coord] = fake_id++; - } - } - } - std::vector> rc_segment_list; - { - // 生成线长为0的线段 - for (auto& [coord, real_pin_list] : coord_real_pin_map) { - for (size_t i = 1; i < real_pin_list.size(); i++) { - RCPin first_rc_pin(coord, true, RTUTIL.escapeBackslash(real_pin_list[i - 1])); - RCPin second_rc_pin(coord, true, RTUTIL.escapeBackslash(real_pin_list[i])); - rc_segment_list.emplace_back(first_rc_pin, second_rc_pin); - } - } - // 生成线长大于0的线段 - for (Segment& routing_segment : routing_segment_list) { - auto getRCPin = [&](LayerCoord& coord) { - RCPin rc_pin; - if (RTUTIL.exist(coord_real_pin_map, coord)) { - rc_pin = RCPin(coord, true, RTUTIL.escapeBackslash(coord_real_pin_map[coord].front())); - } else if (RTUTIL.exist(coord_fake_pin_map, coord)) { - rc_pin = RCPin(coord, false, coord_fake_pin_map[coord]); - } else { - RTLOG.error(Loc::current(), "The coord is not exist!"); - } - return rc_pin; - }; - rc_segment_list.emplace_back(getRCPin(routing_segment.get_first()), getRCPin(routing_segment.get_second())); - } - } - return rc_segment_list; - }; - auto getRctNode = [](ista::TimingEngine* timing_engine, ista::Netlist* sta_net_list, ista::Net* ista_net, RCPin& rc_pin) { - ista::RctNode* rct_node = nullptr; - if (rc_pin._is_real_pin) { - ista::DesignObject* pin_port = nullptr; - auto pin_port_list = sta_net_list->findPin(rc_pin._pin_name.c_str(), false, false); - if (!pin_port_list.empty()) { - pin_port = pin_port_list.front(); - } else { - pin_port = sta_net_list->findPort(rc_pin._pin_name.c_str()); - } - rct_node = timing_engine->makeOrFindRCTreeNode(pin_port); - } else { - rct_node = timing_engine->makeOrFindRCTreeNode(ista_net, rc_pin._fake_pin_id); - } - return rct_node; - }; -#endif - -#if 1 // 预处理流程 - // 每个pin只留一个连通的坐标 - for (size_t i = 0; i < real_pin_coord_map_list.size(); i++) { - std::vector>& routing_segment_list = routing_segment_list_list[i]; - for (auto& [pin_name, coord_list] : real_pin_coord_map_list[i]) { - if (coord_list.size() < 2) { - continue; - } - if (routing_segment_list.empty()) { - coord_list.erase(coord_list.begin() + 1, coord_list.end()); - } else { - for (LayerCoord& coord : coord_list) { - bool is_exist = false; - for (Segment& routing_segment : routing_segment_list) { - if (coord == routing_segment.get_first() || coord == routing_segment.get_second()) { - is_exist = true; - break; - } - } - if (is_exist) { - coord_list[0] = coord; - coord_list.erase(coord_list.begin() + 1, coord_list.end()); - break; - } - } - } - if (coord_list.size() > 2) { - RTLOG.error(Loc::current(), "The pin ", pin_name, " is not in segment_list"); - } - } - } - // coord_real_pin_map_list - std::vector, CmpLayerCoordByXASC>> coord_real_pin_map_list; - coord_real_pin_map_list.resize(real_pin_coord_map_list.size()); - for (size_t i = 0; i < real_pin_coord_map_list.size(); i++) { - for (auto& [real_pin, coord_list] : real_pin_coord_map_list[i]) { - for (LayerCoord& coord : coord_list) { - coord_real_pin_map_list[i][coord].push_back(real_pin); - } - } - } -#endif - -#if 1 // 主流程 - std::vector& net_list = RTDM.getDatabase().get_net_list(); - std::string& temp_directory_path = RTDM.getConfig().temp_directory_path; - - ista::TimingEngine* timing_engine = initTimingEngine(RTUTIL.getString(temp_directory_path, "other_tools/ista/")); - ista::Netlist* sta_net_list = timing_engine->get_netlist(); - - for (size_t net_idx = 0; net_idx < coord_real_pin_map_list.size(); net_idx++) { - ista::Net* ista_net = sta_net_list->findNet(RTUTIL.escapeBackslash(net_list[net_idx].get_net_name()).c_str()); - timing_engine->resetRcTree(ista_net); - for (Segment& segment : getRCSegmentList(coord_real_pin_map_list[net_idx], routing_segment_list_list[net_idx])) { - RCPin& first_rc_pin = segment.get_first(); - RCPin& second_rc_pin = segment.get_second(); - - double cap = 0; - double res = 0; - if (first_rc_pin._coord.get_layer_idx() == second_rc_pin._coord.get_layer_idx()) { - int32_t distance = RTUTIL.getManhattanDistance(first_rc_pin._coord, second_rc_pin._coord); - int32_t unit = dmInst->get_idb_def_service()->get_design()->get_units()->get_micron_dbu(); - std::optional width = std::nullopt; - cap = dynamic_cast(timing_engine->get_db_adapter()) - ->getCapacitance(first_rc_pin._coord.get_layer_idx() + 1, distance / 1.0 / unit, width); - res = dynamic_cast(timing_engine->get_db_adapter()) - ->getResistance(first_rc_pin._coord.get_layer_idx() + 1, distance / 1.0 / unit, width); - } - - ista::RctNode* first_node = getRctNode(timing_engine, sta_net_list, ista_net, first_rc_pin); - ista::RctNode* second_node = getRctNode(timing_engine, sta_net_list, ista_net, second_rc_pin); - timing_engine->makeResistor(ista_net, first_node, second_node, res); - timing_engine->incrCap(first_node, cap / 2, true); - timing_engine->incrCap(second_node, cap / 2, true); - } - timing_engine->updateRCTreeInfo(ista_net); - // auto* rc_tree = timing_engine->get_ista()->getRcNet(ista_net)->rct(); - // rc_tree->printGraphViz(); - // int32_t a = 0; - // dot -Tpdf tree.dot -o tree.pdf - } - timing_engine->updateTiming(); - timing_engine->reportTiming(); - - auto clk_list = timing_engine->getClockList(); - std::ranges::for_each(clk_list, [&](ista::StaClock* clk) { - auto clk_name = clk->get_clock_name(); - auto setup_tns = timing_engine->getTNS(clk_name, AnalysisMode::kMax); - auto setup_wns = timing_engine->getWNS(clk_name, AnalysisMode::kMax); - auto suggest_freq = 1000.0 / (clk->getPeriodNs() - setup_wns); - clock_timing[clk_name]["TNS"] = setup_tns; - clock_timing[clk_name]["WNS"] = setup_wns; - clock_timing[clk_name]["Freq(MHz)"] = suggest_freq; - }); -#endif -#endif -} - -#endif - #endif // private diff --git a/src/operation/iRT/interface/RTInterface.hpp b/src/operation/iRT/interface/RTInterface.hpp index f73f7853e5..84749c2c0f 100644 --- a/src/operation/iRT/interface/RTInterface.hpp +++ b/src/operation/iRT/interface/RTInterface.hpp @@ -146,12 +146,6 @@ class RTInterface ids::Shape getIDSShape(int32_t net_idx, LayerRect layer_rect, bool is_routing); #endif -#if 1 // iSTA - void updateTiming(std::vector>>& real_pin_coord_map_list, - std::vector>>& routing_segment_list_list, - std::map>& clock_timing); -#endif - #endif private: diff --git a/src/operation/iRT/source/data_manager/DataManager.cpp b/src/operation/iRT/source/data_manager/DataManager.cpp index c8bedf425f..40fa463f12 100644 --- a/src/operation/iRT/source/data_manager/DataManager.cpp +++ b/src/operation/iRT/source/data_manager/DataManager.cpp @@ -1309,8 +1309,6 @@ void DataManager::printConfig() RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(2), _config.top_routing_layer); RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(1), "output_inter_result"); RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(2), _config.output_inter_result); - RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(1), "enable_timing"); - RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(2), _config.enable_timing); // ********** RT ********** // RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(0), "RT_CONFIG_BUILD"); RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(1), "log_file_path"); diff --git a/src/operation/iRT/source/data_manager/advance/Config.hpp b/src/operation/iRT/source/data_manager/advance/Config.hpp index e79f245588..8a95abd5a7 100644 --- a/src/operation/iRT/source/data_manager/advance/Config.hpp +++ b/src/operation/iRT/source/data_manager/advance/Config.hpp @@ -32,7 +32,6 @@ class Config std::string bottom_routing_layer; // optional std::string top_routing_layer; // optional int32_t output_inter_result; // optional - int32_t enable_timing; // optional ///////////////////////////////////////////// // ********** RT ********** // std::string log_file_path; // building diff --git a/src/operation/iRT/source/data_manager/advance/Summary.hpp b/src/operation/iRT/source/data_manager/advance/Summary.hpp index 6a5a82126f..53f9d0efc6 100644 --- a/src/operation/iRT/source/data_manager/advance/Summary.hpp +++ b/src/operation/iRT/source/data_manager/advance/Summary.hpp @@ -52,7 +52,6 @@ class PRSummary double total_demand = 0; double total_overflow = 0; double total_wire_length = 0; - std::map> clock_timing_map; }; class LASummary @@ -68,7 +67,6 @@ class LASummary double total_wire_length = 0; std::map cut_via_num_map; int32_t total_via_num = 0; - std::map> clock_timing_map; }; class SRSummary @@ -84,7 +82,6 @@ class SRSummary double total_wire_length = 0; std::map cut_via_num_map; int32_t total_via_num = 0; - std::map> clock_timing_map; }; class TASummary @@ -111,7 +108,6 @@ class DRSummary int32_t total_patch_num = 0; std::map routing_violation_num_map; int32_t total_violation_num = 0; - std::map> clock_timing_map; }; class VRSummary @@ -133,7 +129,6 @@ class VRSummary std::map among_net_violation_type_num_map; std::map among_net_routing_violation_num_map; int32_t among_net_total_violation_num = 0; - std::map> clock_timing_map; }; class Summary diff --git a/src/operation/iRT/source/module/detailed_router/DetailedRouter.cpp b/src/operation/iRT/source/module/detailed_router/DetailedRouter.cpp index bd14342b56..e6cb03d5db 100644 --- a/src/operation/iRT/source/module/detailed_router/DetailedRouter.cpp +++ b/src/operation/iRT/source/module/detailed_router/DetailedRouter.cpp @@ -4253,7 +4253,6 @@ void DetailedRouter::updateSummary(DRModel& dr_model) int32_t micron_dbu = RTDM.getDatabase().get_micron_dbu(); std::vector>& layer_via_master_list = RTDM.getDatabase().get_layer_via_master_list(); Summary& summary = RTDM.getDatabase().get_summary(); - int32_t enable_timing = RTDM.getConfig().enable_timing; std::map& routing_wire_length_map = summary.iter_dr_summary_map[dr_model.get_iter()].routing_wire_length_map; double& total_wire_length = summary.iter_dr_summary_map[dr_model.get_iter()].total_wire_length; @@ -4263,9 +4262,6 @@ void DetailedRouter::updateSummary(DRModel& dr_model) int32_t& total_patch_num = summary.iter_dr_summary_map[dr_model.get_iter()].total_patch_num; std::map& routing_violation_num_map = summary.iter_dr_summary_map[dr_model.get_iter()].routing_violation_num_map; int32_t& total_violation_num = summary.iter_dr_summary_map[dr_model.get_iter()].total_violation_num; - std::map>& clock_timing_map = summary.iter_dr_summary_map[dr_model.get_iter()].clock_timing_map; - - std::vector& dr_net_list = dr_model.get_dr_net_list(); routing_wire_length_map.clear(); total_wire_length = 0; @@ -4275,7 +4271,6 @@ void DetailedRouter::updateSummary(DRModel& dr_model) total_patch_num = 0; routing_violation_num_map.clear(); total_violation_num = 0; - clock_timing_map.clear(); for (auto& [net_idx, segment_list] : dr_model.get_curr_result().get_net_detailed_result_map()) { for (Segment& segment : segment_list) { @@ -4307,23 +4302,6 @@ void DetailedRouter::updateSummary(DRModel& dr_model) routing_violation_num_map[violation.get_violation_shape().get_layer_idx()]++; total_violation_num++; } - if (enable_timing) { - std::vector>> real_pin_coord_map_list; - real_pin_coord_map_list.resize(dr_net_list.size()); - std::vector>> routing_segment_list_list; - routing_segment_list_list.resize(dr_net_list.size()); - for (DRNet& dr_net : dr_net_list) { - for (DRPin& dr_pin : dr_net.get_dr_pin_list()) { - real_pin_coord_map_list[dr_net.get_net_idx()][dr_pin.get_pin_name()].push_back(dr_pin.get_access_point().getRealLayerCoord()); - } - } - for (auto& [net_idx, segment_list] : dr_model.get_curr_result().get_net_detailed_result_map()) { - for (Segment& segment : segment_list) { - routing_segment_list_list[net_idx].emplace_back(segment.get_first(), segment.get_second()); - } - } - RTI.updateTiming(real_pin_coord_map_list, routing_segment_list_list, clock_timing_map); - } } void DetailedRouter::printSummary(DRModel& dr_model) @@ -4331,7 +4309,6 @@ void DetailedRouter::printSummary(DRModel& dr_model) std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::vector& cut_layer_list = RTDM.getDatabase().get_cut_layer_list(); Summary& summary = RTDM.getDatabase().get_summary(); - int32_t enable_timing = RTDM.getConfig().enable_timing; std::map& routing_wire_length_map = summary.iter_dr_summary_map[dr_model.get_iter()].routing_wire_length_map; double& total_wire_length = summary.iter_dr_summary_map[dr_model.get_iter()].total_wire_length; @@ -4341,7 +4318,6 @@ void DetailedRouter::printSummary(DRModel& dr_model) int32_t& total_patch_num = summary.iter_dr_summary_map[dr_model.get_iter()].total_patch_num; std::map& routing_violation_num_map = summary.iter_dr_summary_map[dr_model.get_iter()].routing_violation_num_map; int32_t& total_violation_num = summary.iter_dr_summary_map[dr_model.get_iter()].total_violation_num; - std::map>& clock_timing_map = summary.iter_dr_summary_map[dr_model.get_iter()].clock_timing_map; fort::char_table routing_wire_length_map_table; { @@ -4392,20 +4368,8 @@ void DetailedRouter::printSummary(DRModel& dr_model) routing_violation_num_map_table << fort::header << "Total" << total_violation_num << RTUTIL.getPercentage(total_violation_num, total_violation_num) << fort::endr; } - fort::char_table timing_table; - timing_table.set_cell_text_align(fort::text_align::right); - if (enable_timing) { - timing_table << fort::header << "clock_name" - << "tns" - << "wns" - << "freq" << fort::endr; - for (auto& [clock_name, timing_map] : clock_timing_map) { - timing_table << clock_name << timing_map["TNS"] << timing_map["WNS"] << timing_map["Freq(MHz)"] << fort::endr; - } - } RTUTIL.printTableList({routing_wire_length_map_table, cut_via_num_map_table, routing_patch_num_map_table}); RTUTIL.printTableList({routing_violation_num_map_table}); - RTUTIL.printTableList({timing_table}); } void DetailedRouter::outputNetCSV(DRModel& dr_model) diff --git a/src/operation/iRT/source/module/layer_assigner/LayerAssigner.cpp b/src/operation/iRT/source/module/layer_assigner/LayerAssigner.cpp index 2bb4f296db..e381ea013b 100644 --- a/src/operation/iRT/source/module/layer_assigner/LayerAssigner.cpp +++ b/src/operation/iRT/source/module/layer_assigner/LayerAssigner.cpp @@ -806,11 +806,9 @@ void LayerAssigner::updateRoutingTreeToGraph(LAModel& la_model, const RoutingSeg void LayerAssigner::updateSummary(LAModel& la_model) { int32_t micron_dbu = RTDM.getDatabase().get_micron_dbu(); - ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); GridMap& gcell_map = RTDM.getDatabase().get_gcell_map(); std::vector>& layer_via_master_list = RTDM.getDatabase().get_layer_via_master_list(); Summary& summary = RTDM.getDatabase().get_summary(); - int32_t enable_timing = RTDM.getConfig().enable_timing; std::map& routing_demand_map = summary.la_summary.routing_demand_map; double& total_demand = summary.la_summary.total_demand; @@ -820,9 +818,6 @@ void LayerAssigner::updateSummary(LAModel& la_model) double& total_wire_length = summary.la_summary.total_wire_length; std::map& cut_via_num_map = summary.la_summary.cut_via_num_map; int32_t& total_via_num = summary.la_summary.total_via_num; - std::map>& clock_timing_map = summary.la_summary.clock_timing_map; - - std::vector& la_net_list = la_model.get_la_net_list(); routing_demand_map.clear(); total_demand = 0; @@ -832,7 +827,6 @@ void LayerAssigner::updateSummary(LAModel& la_model) total_wire_length = 0; cut_via_num_map.clear(); total_via_num = 0; - clock_timing_map.clear(); std::vector>& routing_h_edge_map = RTDM.getDatabase().get_routing_h_edge_map(); std::vector>& routing_v_edge_map = RTDM.getDatabase().get_routing_v_edge_map(); @@ -877,31 +871,6 @@ void LayerAssigner::updateSummary(LAModel& la_model) } } } - if (enable_timing) { - std::vector>> real_pin_coord_map_list; - real_pin_coord_map_list.resize(la_net_list.size()); - std::vector>> routing_segment_list_list; - routing_segment_list_list.resize(la_net_list.size()); - for (LANet& la_net : la_net_list) { - for (LAPin& la_pin : la_net.get_la_pin_list()) { - LayerCoord layer_coord = la_pin.get_access_point().getGridLayerCoord(); - real_pin_coord_map_list[la_net.get_net_idx()][la_pin.get_pin_name()].emplace_back(RTUTIL.getRealRectByGCell(layer_coord, gcell_axis).getMidPoint(), - layer_coord.get_layer_idx()); - } - } - for (auto& [net_idx, segment_set] : la_model.get_net_global_result_map()) { - for (Segment& segment_value : segment_set) { - Segment* segment = &segment_value; - LayerCoord first_layer_coord = segment->get_first(); - LayerCoord first_real_coord(RTUTIL.getRealRectByGCell(first_layer_coord, gcell_axis).getMidPoint(), first_layer_coord.get_layer_idx()); - LayerCoord second_layer_coord = segment->get_second(); - LayerCoord second_real_coord(RTUTIL.getRealRectByGCell(second_layer_coord, gcell_axis).getMidPoint(), second_layer_coord.get_layer_idx()); - - routing_segment_list_list[net_idx].emplace_back(first_real_coord, second_real_coord); - } - } - RTI.updateTiming(real_pin_coord_map_list, routing_segment_list_list, clock_timing_map); - } } void LayerAssigner::printSummary(LAModel& la_model) @@ -909,7 +878,6 @@ void LayerAssigner::printSummary(LAModel& la_model) std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::vector& cut_layer_list = RTDM.getDatabase().get_cut_layer_list(); Summary& summary = RTDM.getDatabase().get_summary(); - int32_t enable_timing = RTDM.getConfig().enable_timing; std::map& routing_demand_map = summary.la_summary.routing_demand_map; double& total_demand = summary.la_summary.total_demand; @@ -919,7 +887,6 @@ void LayerAssigner::printSummary(LAModel& la_model) double& total_wire_length = summary.la_summary.total_wire_length; std::map& cut_via_num_map = summary.la_summary.cut_via_num_map; int32_t& total_via_num = summary.la_summary.total_via_num; - std::map>& clock_timing_map = summary.la_summary.clock_timing_map; fort::char_table routing_demand_map_table; { @@ -969,19 +936,7 @@ void LayerAssigner::printSummary(LAModel& la_model) } cut_via_num_map_table << fort::header << "Total" << total_via_num << RTUTIL.getPercentage(total_via_num, total_via_num) << fort::endr; } - fort::char_table timing_table; - timing_table.set_cell_text_align(fort::text_align::right); - if (enable_timing) { - timing_table << fort::header << "clock_name" - << "tns" - << "wns" - << "freq" << fort::endr; - for (auto& [clock_name, timing_map] : clock_timing_map) { - timing_table << clock_name << timing_map["TNS"] << timing_map["WNS"] << timing_map["Freq(MHz)"] << fort::endr; - } - } RTUTIL.printTableList({routing_demand_map_table, routing_overflow_map_table, routing_wire_length_map_table, cut_via_num_map_table}); - RTUTIL.printTableList({timing_table}); } void LayerAssigner::outputGuide(LAModel& la_model) diff --git a/src/operation/iRT/source/module/planar_router/PlanarRouter.cpp b/src/operation/iRT/source/module/planar_router/PlanarRouter.cpp index 0328258468..21e3620e7f 100644 --- a/src/operation/iRT/source/module/planar_router/PlanarRouter.cpp +++ b/src/operation/iRT/source/module/planar_router/PlanarRouter.cpp @@ -1437,22 +1437,16 @@ void PlanarRouter::uploadNetList(PRModel& pr_model, const std::vector& p void PlanarRouter::updateSummary(PRModel& pr_model) { int32_t micron_dbu = RTDM.getDatabase().get_micron_dbu(); - ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); GridMap& gcell_map = RTDM.getDatabase().get_gcell_map(); Summary& summary = RTDM.getDatabase().get_summary(); - int32_t enable_timing = RTDM.getConfig().enable_timing; double& total_demand = summary.pr_summary.total_demand; double& total_overflow = summary.pr_summary.total_overflow; double& total_wire_length = summary.pr_summary.total_wire_length; - std::map>& clock_timing_map = summary.pr_summary.clock_timing_map; - - std::vector& pr_net_list = pr_model.get_pr_net_list(); total_demand = 0; total_overflow = 0; total_wire_length = 0; - clock_timing_map.clear(); for (GridMap* routing_edge_map : {&RTDM.getDatabase().get_planar_routing_h_edge_map(), &RTDM.getDatabase().get_planar_routing_v_edge_map()}) { for (int32_t x = 0; x < routing_edge_map->get_x_size(); x++) { @@ -1481,41 +1475,15 @@ void PlanarRouter::updateSummary(PRModel& pr_model) } } } - if (enable_timing) { - std::vector>> real_pin_coord_map_list; - real_pin_coord_map_list.resize(pr_net_list.size()); - std::vector>> routing_segment_list_list; - routing_segment_list_list.resize(pr_net_list.size()); - for (PRNet& pr_net : pr_net_list) { - for (PRPin& pr_pin : pr_net.get_pr_pin_list()) { - LayerCoord layer_coord = pr_pin.get_access_point().getGridLayerCoord(); - real_pin_coord_map_list[pr_net.get_net_idx()][pr_pin.get_pin_name()].emplace_back(RTUTIL.getRealRectByGCell(layer_coord, gcell_axis).getMidPoint(), 0); - } - } - for (auto& [net_idx, segment_set] : pr_model.get_net_global_result_map()) { - for (Segment& segment_value : segment_set) { - Segment* segment = &segment_value; - LayerCoord first_layer_coord = segment->get_first(); - LayerCoord first_real_coord(RTUTIL.getRealRectByGCell(first_layer_coord, gcell_axis).getMidPoint(), first_layer_coord.get_layer_idx()); - LayerCoord second_layer_coord = segment->get_second(); - LayerCoord second_real_coord(RTUTIL.getRealRectByGCell(second_layer_coord, gcell_axis).getMidPoint(), second_layer_coord.get_layer_idx()); - - routing_segment_list_list[net_idx].emplace_back(first_real_coord, second_real_coord); - } - } - RTI.updateTiming(real_pin_coord_map_list, routing_segment_list_list, clock_timing_map); - } } void PlanarRouter::printSummary(PRModel& pr_model) { Summary& summary = RTDM.getDatabase().get_summary(); - int32_t enable_timing = RTDM.getConfig().enable_timing; double& total_demand = summary.pr_summary.total_demand; double& total_overflow = summary.pr_summary.total_overflow; double& total_wire_length = summary.pr_summary.total_wire_length; - std::map>& clock_timing_map = summary.pr_summary.clock_timing_map; fort::char_table summary_table; { @@ -1524,19 +1492,7 @@ void PlanarRouter::printSummary(PRModel& pr_model) summary_table << fort::header << "total_overflow" << total_overflow << fort::endr; summary_table << fort::header << "total_wire_length" << total_wire_length << fort::endr; } - fort::char_table timing_table; - timing_table.set_cell_text_align(fort::text_align::right); - if (enable_timing) { - timing_table << fort::header << "clock_name" - << "tns" - << "wns" - << "freq" << fort::endr; - for (auto& [clock_name, timing_map] : clock_timing_map) { - timing_table << clock_name << timing_map["TNS"] << timing_map["WNS"] << timing_map["Freq(MHz)"] << fort::endr; - } - } RTUTIL.printTableList({summary_table}); - RTUTIL.printTableList({timing_table}); } void PlanarRouter::outputGuide(PRModel& pr_model) diff --git a/src/operation/iRT/source/module/violation_reporter/ViolationReporter.cpp b/src/operation/iRT/source/module/violation_reporter/ViolationReporter.cpp index f274a9e58e..0a13322491 100644 --- a/src/operation/iRT/source/module/violation_reporter/ViolationReporter.cpp +++ b/src/operation/iRT/source/module/violation_reporter/ViolationReporter.cpp @@ -175,7 +175,6 @@ void ViolationReporter::updateSummary(VRModel& vr_model) Die& die = RTDM.getDatabase().get_die(); std::vector>& layer_via_master_list = RTDM.getDatabase().get_layer_via_master_list(); Summary& summary = RTDM.getDatabase().get_summary(); - int32_t enable_timing = RTDM.getConfig().enable_timing; std::map& routing_wire_length_map = summary.vr_summary.routing_wire_length_map; double& total_wire_length = summary.vr_summary.total_wire_length; @@ -191,9 +190,6 @@ void ViolationReporter::updateSummary(VRModel& vr_model) std::map& among_net_violation_type_num_map = summary.vr_summary.among_net_violation_type_num_map; std::map& among_net_routing_violation_num_map = summary.vr_summary.among_net_routing_violation_num_map; int32_t& among_net_total_violation_num = summary.vr_summary.among_net_total_violation_num; - std::map>& clock_timing_map = summary.vr_summary.clock_timing_map; - - std::vector& vr_net_list = vr_model.get_vr_net_list(); routing_wire_length_map.clear(); total_wire_length = 0; @@ -209,7 +205,6 @@ void ViolationReporter::updateSummary(VRModel& vr_model) among_net_violation_type_num_map.clear(); among_net_routing_violation_num_map.clear(); among_net_total_violation_num = 0; - clock_timing_map.clear(); for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { for (Segment* segment : segment_set) { @@ -255,23 +250,6 @@ void ViolationReporter::updateSummary(VRModel& vr_model) among_net_routing_violation_num_map[violation.get_violation_shape().get_layer_idx()]++; among_net_total_violation_num++; } - if (enable_timing) { - std::vector>> real_pin_coord_map_list; - real_pin_coord_map_list.resize(vr_net_list.size()); - std::vector>> routing_segment_list_list; - routing_segment_list_list.resize(vr_net_list.size()); - for (VRNet& vr_net : vr_net_list) { - for (VRPin& vr_pin : vr_net.get_vr_pin_list()) { - real_pin_coord_map_list[vr_net.get_net_idx()][vr_pin.get_pin_name()].push_back(vr_pin.get_access_point().getRealLayerCoord()); - } - } - for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { - for (Segment* segment : segment_set) { - routing_segment_list_list[net_idx].emplace_back(segment->get_first(), segment->get_second()); - } - } - RTI.updateTiming(real_pin_coord_map_list, routing_segment_list_list, clock_timing_map); - } } void ViolationReporter::printSummary(VRModel& vr_model) @@ -279,7 +257,6 @@ void ViolationReporter::printSummary(VRModel& vr_model) std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::vector& cut_layer_list = RTDM.getDatabase().get_cut_layer_list(); Summary& summary = RTDM.getDatabase().get_summary(); - int32_t enable_timing = RTDM.getConfig().enable_timing; std::map& routing_wire_length_map = summary.vr_summary.routing_wire_length_map; double& total_wire_length = summary.vr_summary.total_wire_length; @@ -295,7 +272,6 @@ void ViolationReporter::printSummary(VRModel& vr_model) std::map& among_net_violation_type_num_map = summary.vr_summary.among_net_violation_type_num_map; std::map& among_net_routing_violation_num_map = summary.vr_summary.among_net_routing_violation_num_map; int32_t& among_net_total_violation_num = summary.vr_summary.among_net_total_violation_num; - std::map>& clock_timing_map = summary.vr_summary.clock_timing_map; fort::char_table routing_wire_length_map_table; { @@ -385,21 +361,9 @@ void ViolationReporter::printSummary(VRModel& vr_model) } among_net_routing_violation_map_table << fort::header << among_net_total_violation_num << fort::endr; } - fort::char_table timing_table; - timing_table.set_cell_text_align(fort::text_align::right); - if (enable_timing) { - timing_table << fort::header << "clock_name" - << "tns" - << "wns" - << "freq" << fort::endr; - for (auto& [clock_name, timing_map] : clock_timing_map) { - timing_table << clock_name << timing_map["TNS"] << timing_map["WNS"] << timing_map["Freq(MHz)"] << fort::endr; - } - } RTUTIL.printTableList({routing_wire_length_map_table, cut_via_num_map_table, routing_patch_num_map_table}); RTUTIL.printTableList({within_net_routing_violation_map_table}); RTUTIL.printTableList({among_net_routing_violation_map_table}); - RTUTIL.printTableList({timing_table}); } void ViolationReporter::outputNetCSV(VRModel& vr_model) diff --git a/test/fixtures/gcd/config/route_ecc.json b/test/fixtures/gcd/config/route_ecc.json index 4d93889b09..51daf88c4b 100644 --- a/test/fixtures/gcd/config/route_ecc.json +++ b/test/fixtures/gcd/config/route_ecc.json @@ -4,8 +4,7 @@ "-bottom_routing_layer": "MET2", "-top_routing_layer": "MET5", "-thread_number": "50", - "-enable_timing": "0", "-output_csv": "0", "-output_inter_result": "0" } -} \ No newline at end of file +} From d36517208fdbc1caecfa9af51737400d34309b1a Mon Sep 17 00:00:00 2001 From: ZhishengZeng Date: Tue, 15 Sep 2026 11:06:40 +0800 Subject: [PATCH 3/5] refactor(py_irt): align commands and flags with Tcl --- src/interface/python/py_irt/py_irt.cpp | 38 +++-- src/interface/python/py_irt/py_irt.h | 4 +- src/interface/python/py_irt/py_irt_utils.cpp | 141 ++++++++---------- src/interface/python/py_irt/py_register_irt.h | 5 +- test/fixtures/gcd/config/route_ecc.json | 1 - 5 files changed, 89 insertions(+), 100 deletions(-) diff --git a/src/interface/python/py_irt/py_irt.cpp b/src/interface/python/py_irt/py_irt.cpp index 6d8955d968..b41bae7bc5 100644 --- a/src/interface/python/py_irt/py_irt.cpp +++ b/src/interface/python/py_irt/py_irt.cpp @@ -16,18 +16,27 @@ // *************************************************************************************** #include "py_irt.h" -#include - #include #include "RTInterface.hpp" + namespace python_interface { -bool initConfigMapByJSON(const std::string& config, std::map& config_map); +bool initRTConfigMapByJSON(const std::string& config, std::map& config_map); +void initRTConfigMapByDict(std::map& config_dict, std::map& config_map); +bool initERTConfigMapByJSON(const std::string& config, std::map& config_map); +void initERTConfigMapByDict(std::map& config_dict, std::map& config_map); -bool destroyRT() +bool initRT(std::string& config, std::map& config_dict) { - RTI.destroyRT(); + std::map config_map; + + bool pass = config.empty() ? true : initRTConfigMapByJSON(config, config_map); + if (!pass) { + return false; + } + initRTConfigMapByDict(config_dict, config_map); + RTI.initRT(config_map); return true; } @@ -35,11 +44,11 @@ bool runERT(std::string& config, std::map& config_dict { std::map config_map; - bool pass = false; - pass = !pass ? initConfigMapByJSON(config, config_map) : pass; + bool pass = config.empty() ? true : initERTConfigMapByJSON(config, config_map); if (!pass) { return false; } + initERTConfigMapByDict(config_dict, config_map); RTI.runERT(config_map); return true; } @@ -50,16 +59,15 @@ bool runRT() return true; } -bool initRT(std::string& config, std::map& config_dict) +bool destroyRT() { - std::map config_map; + RTI.destroyRT(); + return true; +} - bool pass = false; - pass = !pass ? initConfigMapByJSON(config, config_map) : pass; - if (!pass) { - return false; - } - RTI.initRT(config_map); +bool cleanDef() +{ + RTI.cleanDef(); return true; } diff --git a/src/interface/python/py_irt/py_irt.h b/src/interface/python/py_irt/py_irt.h index fb74fff1f6..b98377bde4 100644 --- a/src/interface/python/py_irt/py_irt.h +++ b/src/interface/python/py_irt/py_irt.h @@ -20,10 +20,10 @@ namespace python_interface { -bool destroyRT(); bool initRT(std::string& config, std::map& config_dict); -bool runDR(); bool runERT(std::string& config, std::map& config_dict); bool runRT(); +bool destroyRT(); +bool cleanDef(); } // namespace python_interface diff --git a/src/interface/python/py_irt/py_irt_utils.cpp b/src/interface/python/py_irt/py_irt_utils.cpp index 86e52cb659..37dfabb267 100644 --- a/src/interface/python/py_irt/py_irt_utils.cpp +++ b/src/interface/python/py_irt/py_irt_utils.cpp @@ -14,82 +14,64 @@ // // See the Mulan PSL v2 for more details. // *************************************************************************************** -#include - #include -#include "RTInterface.hpp" #include "json_parser.h" #include "py_irt.h" namespace python_interface { -using tcl::ValueType; - -std::map strToDoubleMap(const std::string& input) -{ - // Trim the leading and trailing whitespaces from the input - std::string input_trimmed = input; - input_trimmed.erase(input_trimmed.begin(), - std::find_if(input_trimmed.begin(), input_trimmed.end(), [](int ch) { return !std::isspace(ch); })); - input_trimmed.erase(std::find_if(input_trimmed.rbegin(), input_trimmed.rend(), [](int ch) { return !std::isspace(ch); }).base(), - input_trimmed.end()); - std::map result; - std::stringstream ss(input_trimmed.substr(1, input_trimmed.length() - 2)); - std::string item; - while (std::getline(ss, item, ',')) { - size_t pos = item.find(":"); - std::string key = item.substr(0, pos); - // Trim whitespaces from the key and value - key.erase(std::remove_if(key.begin(), key.end(), [](unsigned char c) { return std::isspace(c); }), key.end()); - std::string value_str = item.substr(pos + 1); - value_str.erase(std::remove_if(value_str.begin(), value_str.end(), [](unsigned char c) { return std::isspace(c); }), value_str.end()); - double value = std::stod(value_str); - result[key] = value; - } - return result; -} - -std::vector strToVector(const std::string& input) +bool initRTConfigMapByJSON(const std::string& config, std::map& config_map) { - std::vector result; - std::string token; - for (char c : input) { - switch (c) { - case ' ': - case ',': { - if (!token.empty()) { - result.push_back(token); - token.clear(); - } - break; - } - default: - token.push_back(c); - } - } - return result; -} + auto config_file = std::ifstream(config); + if (!config_file.is_open()) { + return false; + } + nlohmann::json json; + config_file >> json; + std::string value = ecc::getJsonData(json, {"RT", "-temp_directory_path"}); + if (!value.empty()) { + config_map["-temp_directory_path"] = value; + } + value = ecc::getJsonData(json, {"RT", "-bottom_routing_layer"}); + if (!value.empty()) { + config_map["-bottom_routing_layer"] = value; + } + value = ecc::getJsonData(json, {"RT", "-top_routing_layer"}); + if (!value.empty()) { + config_map["-top_routing_layer"] = value; + } + value = ecc::getJsonData(json, {"RT", "-thread_number"}); + if (!value.empty()) { + config_map["-thread_number"] = std::stoi(value); + } + value = ecc::getJsonData(json, {"RT", "-output_inter_result"}); + if (!value.empty()) { + config_map["-output_inter_result"] = std::stoi(value); + } -std::vector strToDoubleVec(const std::string& input) -{ - auto tmp = strToVector(input); - std::vector result; - result.reserve(tmp.size()); - for_each(tmp.begin(), tmp.end(), [&result](const std::string& s) { result.push_back(std::stod(s)); }); - return result; + return true; } -std::vector strToIntVec(const std::string& input) +void initRTConfigMapByDict(std::map& config_dict, std::map& config_map) { - auto tmp = strToVector(input); - std::vector result; - result.reserve(tmp.size()); - for_each(tmp.begin(), tmp.end(), [&result](const std::string& s) { result.push_back(std::stoi(s)); }); - return result; + if (config_dict.count("-temp_directory_path") > 0 && !config_dict["-temp_directory_path"].empty()) { + config_map["-temp_directory_path"] = config_dict["-temp_directory_path"]; + } + if (config_dict.count("-bottom_routing_layer") > 0 && !config_dict["-bottom_routing_layer"].empty()) { + config_map["-bottom_routing_layer"] = config_dict["-bottom_routing_layer"]; + } + if (config_dict.count("-top_routing_layer") > 0 && !config_dict["-top_routing_layer"].empty()) { + config_map["-top_routing_layer"] = config_dict["-top_routing_layer"]; + } + if (config_dict.count("-thread_number") > 0 && !config_dict["-thread_number"].empty()) { + config_map["-thread_number"] = std::stoi(config_dict["-thread_number"]); + } + if (config_dict.count("-output_inter_result") > 0 && !config_dict["-output_inter_result"].empty()) { + config_map["-output_inter_result"] = std::stoi(config_dict["-output_inter_result"]); + } } -// 通过json文件对config进行初始化 -bool initConfigMapByJSON(const std::string& config, std::map& config_map) +bool initERTConfigMapByJSON(const std::string& config, std::map& config_map) { auto config_file = std::ifstream(config); if (!config_file.is_open()) { @@ -97,27 +79,26 @@ bool initConfigMapByJSON(const std::string& config, std::map> json; - nlohmann::json rt_json = json["RT"]; - std::string value; - value = ecc::getJsonData(json, {"RT", "-temp_directory_path"}); - config_map.insert(std::make_pair("-temp_directory_path", value)); - value = ecc::getJsonData(json, {"RT", "-bottom_routing_layer"}); - config_map.insert(std::make_pair("-bottom_routing_layer", value)); - value = ecc::getJsonData(json, {"RT", "-top_routing_layer"}); - config_map.insert(std::make_pair("-top_routing_layer", value)); - value = ecc::getJsonData(json, {"RT", "-thread_number"}); - config_map.insert(std::make_pair("-thread_number", std::stoi(value))); - value = ecc::getJsonData(json, {"RT", "-output_inter_result"}); - config_map.insert(std::make_pair("-output_inter_result", std::stoi(value))); - if (json.contains("RT") && json["RT"].contains("-enable_fast_mode")) { - value = ecc::getJsonData(json, {"RT", "-enable_fast_mode"}); - config_map.insert(std::make_pair("-enable_fast_mode", std::stoi(value))); + std::string value = ecc::getJsonData(json, {"RT", "-stage"}); + if (!value.empty()) { + config_map["-stage"] = value; } - for (nlohmann::json::iterator item = rt_json.begin(); item != rt_json.end(); ++item) { - config_map.insert(std::make_pair(item.key(), item.value())); + value = ecc::getJsonData(json, {"RT", "-resolve_congestion"}); + if (!value.empty()) { + config_map["-resolve_congestion"] = value; } return true; } +void initERTConfigMapByDict(std::map& config_dict, std::map& config_map) +{ + if (config_dict.count("-stage") > 0 && !config_dict["-stage"].empty()) { + config_map["-stage"] = config_dict["-stage"]; + } + if (config_dict.count("-resolve_congestion") > 0 && !config_dict["-resolve_congestion"].empty()) { + config_map["-resolve_congestion"] = config_dict["-resolve_congestion"]; + } +} + } // namespace python_interface diff --git a/src/interface/python/py_irt/py_register_irt.h b/src/interface/python/py_irt/py_register_irt.h index 04b3becf3f..3e42d7d483 100644 --- a/src/interface/python/py_irt/py_register_irt.h +++ b/src/interface/python/py_irt/py_register_irt.h @@ -24,9 +24,10 @@ namespace python_interface { namespace py = pybind11; void register_irt(py::module& m) { - m.def("destroy_rt", destroyRT); m.def("init_rt", initRT, py::arg("config") = "", py::arg("config_dict") = std::map{}); m.def("run_ert", runERT, py::arg("config") = "", py::arg("config_dict") = std::map{}); m.def("run_rt", runRT); + m.def("destroy_rt", destroyRT); + m.def("rt_clean_def", cleanDef); } -} // namespace python_interface \ No newline at end of file +} // namespace python_interface diff --git a/test/fixtures/gcd/config/route_ecc.json b/test/fixtures/gcd/config/route_ecc.json index 51daf88c4b..1416232123 100644 --- a/test/fixtures/gcd/config/route_ecc.json +++ b/test/fixtures/gcd/config/route_ecc.json @@ -4,7 +4,6 @@ "-bottom_routing_layer": "MET2", "-top_routing_layer": "MET5", "-thread_number": "50", - "-output_csv": "0", "-output_inter_result": "0" } } From 27d4a8702caa27573b2593e874a3eeb509a01d54 Mon Sep 17 00:00:00 2001 From: ZhishengZeng Date: Tue, 15 Sep 2026 12:11:47 +0800 Subject: [PATCH 4/5] refactor(iRT): remove obsolete DEF cleanup command --- src/interface/python/py_irt/py_irt.cpp | 6 -- src/interface/python/py_irt/py_irt.h | 1 - src/interface/python/py_irt/py_register_irt.h | 1 - src/interface/tcl/tcl_irt/CMakeLists.txt | 1 - .../tcl/tcl_irt/include/tcl_register_irt.h | 2 - src/interface/tcl/tcl_irt/include/tcl_rt.h | 18 ---- .../tcl/tcl_irt/src/tcl_rt_clean_def.cpp | 38 ------- src/operation/iRT/interface/RTInterface.cpp | 98 ------------------- src/operation/iRT/interface/RTInterface.hpp | 1 - 9 files changed, 166 deletions(-) delete mode 100644 src/interface/tcl/tcl_irt/src/tcl_rt_clean_def.cpp diff --git a/src/interface/python/py_irt/py_irt.cpp b/src/interface/python/py_irt/py_irt.cpp index b41bae7bc5..ba2b1d21ac 100644 --- a/src/interface/python/py_irt/py_irt.cpp +++ b/src/interface/python/py_irt/py_irt.cpp @@ -65,10 +65,4 @@ bool destroyRT() return true; } -bool cleanDef() -{ - RTI.cleanDef(); - return true; -} - } // namespace python_interface diff --git a/src/interface/python/py_irt/py_irt.h b/src/interface/python/py_irt/py_irt.h index b98377bde4..c685084eb3 100644 --- a/src/interface/python/py_irt/py_irt.h +++ b/src/interface/python/py_irt/py_irt.h @@ -24,6 +24,5 @@ bool initRT(std::string& config, std::map& config_dict bool runERT(std::string& config, std::map& config_dict); bool runRT(); bool destroyRT(); -bool cleanDef(); } // namespace python_interface diff --git a/src/interface/python/py_irt/py_register_irt.h b/src/interface/python/py_irt/py_register_irt.h index 3e42d7d483..6369769680 100644 --- a/src/interface/python/py_irt/py_register_irt.h +++ b/src/interface/python/py_irt/py_register_irt.h @@ -28,6 +28,5 @@ void register_irt(py::module& m) m.def("run_ert", runERT, py::arg("config") = "", py::arg("config_dict") = std::map{}); m.def("run_rt", runRT); m.def("destroy_rt", destroyRT); - m.def("rt_clean_def", cleanDef); } } // namespace python_interface diff --git a/src/interface/tcl/tcl_irt/CMakeLists.txt b/src/interface/tcl/tcl_irt/CMakeLists.txt index 7ac90d0423..1550ab870e 100644 --- a/src/interface/tcl/tcl_irt/CMakeLists.txt +++ b/src/interface/tcl/tcl_irt/CMakeLists.txt @@ -3,7 +3,6 @@ add_library(tcl_irt ${HOME_INTERFACE}/tcl/tcl_irt/src/tcl_run_ert.cpp ${HOME_INTERFACE}/tcl/tcl_irt/src/tcl_run_rt.cpp ${HOME_INTERFACE}/tcl/tcl_irt/src/tcl_destroy_rt.cpp - ${HOME_INTERFACE}/tcl/tcl_irt/src/tcl_rt_clean_def.cpp ) target_link_libraries(tcl_irt diff --git a/src/interface/tcl/tcl_irt/include/tcl_register_irt.h b/src/interface/tcl/tcl_irt/include/tcl_register_irt.h index bd645bacb1..8ee421809a 100644 --- a/src/interface/tcl/tcl_irt/include/tcl_register_irt.h +++ b/src/interface/tcl/tcl_irt/include/tcl_register_irt.h @@ -29,8 +29,6 @@ int registerCmdRT() registerTclCmd(TclRunERT, "run_ert"); registerTclCmd(TclRunRT, "run_rt"); registerTclCmd(TclDestroyRT, "destroy_rt"); - // aux - registerTclCmd(TclRTCleanDef, "rt_clean_def"); return EXIT_SUCCESS; } diff --git a/src/interface/tcl/tcl_irt/include/tcl_rt.h b/src/interface/tcl/tcl_irt/include/tcl_rt.h index ab5c90862b..ce63abd6c2 100644 --- a/src/interface/tcl/tcl_irt/include/tcl_rt.h +++ b/src/interface/tcl/tcl_irt/include/tcl_rt.h @@ -80,22 +80,4 @@ class TclDestroyRT : public TclCmd #endif -#if 1 // aux - -class TclRTCleanDef : public TclCmd -{ - public: - explicit TclRTCleanDef(const char* cmd_name); - ~TclRTCleanDef() override = default; - - unsigned check() override { return 1; }; - - unsigned exec() override; - - private: - std::vector> _config_list; -}; - -#endif - } // namespace tcl diff --git a/src/interface/tcl/tcl_irt/src/tcl_rt_clean_def.cpp b/src/interface/tcl/tcl_irt/src/tcl_rt_clean_def.cpp deleted file mode 100644 index 34c15aead2..0000000000 --- a/src/interface/tcl/tcl_irt/src/tcl_rt_clean_def.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// *************************************************************************************** -// Copyright (c) 2023-2025 Peng Cheng Laboratory -// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences -// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip -// -// iEDA is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// -// See the Mulan PSL v2 for more details. -// *************************************************************************************** -#include "RTInterface.hpp" -#include "tcl_rt.h" -#include "tcl_util.h" - -namespace tcl { - -TclRTCleanDef::TclRTCleanDef(const char* cmd_name) : TclCmd(cmd_name) -{ -} - -unsigned TclRTCleanDef::exec() -{ - if (!check()) { - return 0; - } - - RTI.cleanDef(); - - return 1; -} - -} // namespace tcl diff --git a/src/operation/iRT/interface/RTInterface.cpp b/src/operation/iRT/interface/RTInterface.cpp index 3b944a15bc..285ee28c59 100644 --- a/src/operation/iRT/interface/RTInterface.cpp +++ b/src/operation/iRT/interface/RTInterface.cpp @@ -183,104 +183,6 @@ void RTInterface::destroyRT() Logger::destroyInst(); } -void RTInterface::cleanDef() -{ -#if 1 - - ////////////////////////////////////////// - // 删除net内所有的wire - auto* idb_design = dmInst->get_idb_def_service()->get_design(); - IdbNetList* idb_net_list = idb_design->get_net_list(); - for (idb::IdbNet* idb_net : idb_net_list->get_net_list()) { - idb_net->clear_wire_list(); - } - // 删除net内所有的wire - ////////////////////////////////////////// - - ////////////////////////////////////////// - // 删除虚空的io_pin - idb::IdbPins* idb_pin_list = idb_design->get_io_pin_list(); - std::vector remove_pin_list; - for (idb::IdbPin* io_pin : idb_pin_list->get_pin_list()) { - if (io_pin->get_port_box_list().empty()) { - RTLOG.info(Loc::current(), "del io_pin: ", io_pin->get_pin_name()); - remove_pin_list.push_back(io_pin); - } - } - for (idb::IdbPin* io_pin : remove_pin_list) { - idb_design->removeIoPinSafe(io_pin); - } - // 删除虚空的io_pin - ////////////////////////////////////////// - -#endif - -#if 0 - - ////////////////////////////////////////// - // 删除net内所有的virtual - for (idb::IdbNet* idb_net : idb_net_list->get_net_list()) { - for (idb::IdbRegularWire* wire : idb_net->get_wire_list()->get_wire_list()) { - std::vector del_segment_list; - for (idb::IdbRegularWireSegment* segment : wire->get_segment_list()) { - if (segment->is_virtual(segment->get_point_second())) { - del_segment_list.push_back(segment); - } - } - for (idb::IdbRegularWireSegment* segment : del_segment_list) { - wire->delete_seg(segment); - } - } - } - // 删除net内所有的virtual - ////////////////////////////////////////// - - ////////////////////////////////////////// - // 删除net内所有的patch - for (idb::IdbNet* idb_net : idb_net_list->get_net_list()) { - for (idb::IdbRegularWire* wire : idb_net->get_wire_list()->get_wire_list()) { - std::vector del_segment_list; - for (idb::IdbRegularWireSegment* segment : wire->get_segment_list()) { - if (segment->is_rect()) { - del_segment_list.push_back(segment); - } - } - for (idb::IdbRegularWireSegment* segment : del_segment_list) { - wire->delete_seg(segment); - } - } - } - // 删除net内所有的patch - ////////////////////////////////////////// - - ////////////////////////////////////////// - // 删除net: 虚拟的io_pin与io_cell连接的PAD - std::vector remove_net_list; - for (idb::IdbNet* idb_net : idb_net_list->get_net_list()) { - bool has_io_pin = idb_net != nullptr && idb_net->has_io_pins(); - bool has_io_cell = false; - if (idb_net != nullptr && idb_net->get_instance_list() != nullptr) { - for (idb::IdbInstance* instance : idb_net->get_instance_list()->get_instance_list()) { - if (instance != nullptr && instance->get_cell_master() != nullptr && instance->get_cell_master()->is_pad()) { - has_io_cell = true; - break; - } - } - } - if (has_io_pin && has_io_cell) { - RTLOG.info(Loc::current(), "The net '", idb_net->get_net_name(), "' connects PAD and io_pin! removing..."); - remove_net_list.push_back(idb_net->get_net_name()); - } - } - for (std::string remove_net : remove_net_list) { - idb_design->removeNetSafe(remove_net); - } - // 删除net: 虚拟的io_pin与io_cell连接的PAD - ////////////////////////////////////////// - -#endif -} - #endif #endif diff --git a/src/operation/iRT/interface/RTInterface.hpp b/src/operation/iRT/interface/RTInterface.hpp index 84749c2c0f..06c6f74a51 100644 --- a/src/operation/iRT/interface/RTInterface.hpp +++ b/src/operation/iRT/interface/RTInterface.hpp @@ -81,7 +81,6 @@ class RTInterface void runERT(std::map config_map); void runRT(); void destroyRT(); - void cleanDef(); #endif #endif From 085ece843e5e9b49806e61a1c307b527f7242dd6 Mon Sep 17 00:00:00 2001 From: SuanQ1212 <572942506@qq.com> Date: Wed, 16 Sep 2026 11:39:39 +0800 Subject: [PATCH 5/5] Boost 192 -> Boost 191 --- .github/actions/build-wheel/action.yml | 23 ++++++++++++----------- CMakeLists.txt | 6 +++--- 2 files changed, 15 insertions(+), 14 deletions(-) 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