Skip to content

Commit 34b8e13

Browse files
remove functionally redundant parts via mass ablation
1 parent c0faf4f commit 34b8e13

11 files changed

Lines changed: 140 additions & 634 deletions

vpr/src/analytical_place/global_placement/affinity_spring_term.cpp

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,13 @@
1212
using vtr::ap::affinity_spring_curvature;
1313

1414
AffinitySpringTerm::AffinitySpringTerm(const APNetlist& ap_netlist,
15-
double io_pair_attraction_weight,
1615
double pack_pattern_weight)
17-
: io_pair_attraction_weight_(io_pair_attraction_weight)
18-
, pack_pattern_weight_(pack_pattern_weight)
16+
: pack_pattern_weight_(pack_pattern_weight)
1917
, moveable_(ap_netlist.blocks().size(), false) {
2018
for (APBlockId blk_id : ap_netlist.blocks())
2119
moveable_[blk_id] = ap_netlist.block_mobility(blk_id) == APBlockMobility::MOVEABLE;
2220
}
2321

24-
double AffinitySpringTerm::kernel_weight_(e_affinity_kind kind) const {
25-
switch (kind) {
26-
case e_affinity_kind::IO_PAIR:
27-
// Legacy I/O pair spring used grad += W * dx (no 1/n). Pack-math kernel
28-
// uses W_kernel / n; for n=2 set W_kernel = 2W to preserve strength.
29-
return 2. * io_pair_attraction_weight_;
30-
case e_affinity_kind::PACK_PATTERN:
31-
return pack_pattern_weight_;
32-
default:
33-
VTR_ASSERT_MSG(false, "Unhandled affinity kind");
34-
return 0.;
35-
}
36-
}
37-
3822
double AffinitySpringTerm::evaluate(const PartialPlacement& p_placement,
3923
std::optional<std::reference_wrapper<PlacementGradient>> grad) const {
4024
if (groups_.empty())
@@ -43,7 +27,7 @@ double AffinitySpringTerm::evaluate(const PartialPlacement& p_placement,
4327
double weighted_penalty = 0.;
4428
for (const AffinityGroup& group : groups_) {
4529
VTR_ASSERT_SAFE(group.blocks.size() >= 2);
46-
double weight = kernel_weight_(group.kind);
30+
double weight = pack_pattern_weight_;
4731
if (weight == 0.)
4832
continue;
4933

@@ -75,7 +59,7 @@ double AffinitySpringTerm::evaluate(const PartialPlacement& p_placement,
7559

7660
void AffinitySpringTerm::add_curvature(vtr::vector<APBlockId, double>& diagonal) const {
7761
for (const AffinityGroup& group : groups_) {
78-
double curvature = affinity_spring_curvature(kernel_weight_(group.kind),
62+
double curvature = affinity_spring_curvature(pack_pattern_weight_,
7963
group.blocks.size());
8064
if (curvature == 0.)
8165
continue;

vpr/src/analytical_place/global_placement/affinity_spring_term.h

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,44 +5,31 @@
55
* @date August 2026
66
* @brief Quadratic centroid affinity-spring objective term.
77
*
8-
* Groups of AP blocks (direct output-driver↔outpad pairs, long prepacker
9-
* chains) are pulled toward their group centroid by a quadratic spring. Group
10-
* *detection* stays with its producers (the placer's io-pair/pack-pattern
11-
* initialization); this term owns the groups' energy, gradient, and
12-
* preconditioner contribution.
8+
* Groups of AP blocks (long prepacker chains) are pulled toward their group
9+
* centroid by a quadratic spring. Group *detection* stays with its producer
10+
* (the placer's pack-pattern initialization); this term owns the groups'
11+
* energy, gradient, and preconditioner contribution.
1312
*/
1413

1514
#include <vector>
1615
#include "objective_term.h"
1716

18-
/**
19-
* @brief Affinity-spring detector kind (logging / per-kind weights).
20-
*/
21-
enum class e_affinity_kind {
22-
IO_PAIR, ///< Direct 2-pin output-driver↔outpad pairs.
23-
PACK_PATTERN ///< Long prepacker chain groups spanning multiple AP blocks.
24-
};
25-
2617
/**
2718
* @brief A set of AP blocks pulled together by a quadratic centroid spring.
2819
*/
2920
struct AffinityGroup {
30-
e_affinity_kind kind = e_affinity_kind::IO_PAIR; ///< Detector that created this group.
31-
std::vector<APBlockId> blocks; ///< AP blocks in the group (size >= 2).
21+
std::vector<APBlockId> blocks; ///< AP blocks in the group (size >= 2).
3222
};
3323

3424
class AffinitySpringTerm final : public ObjectiveTerm {
3525
public:
3626
/**
3727
* @brief Construct with per-kind kernel inputs; precomputes block mobility.
3828
*
39-
* @param io_pair_attraction_weight Legacy per-block I/O pair spring strength
40-
* (the kernel applies 2x for n=2 pack math).
4129
* @param pack_pattern_weight Pack-pattern kernel weight; may later be
4230
* zeroed via @ref set_pack_pattern_weight.
4331
*/
4432
AffinitySpringTerm(const APNetlist& ap_netlist,
45-
double io_pair_attraction_weight,
4633
double pack_pattern_weight);
4734

4835
void clear_groups() { groups_.clear(); }
@@ -71,10 +58,8 @@ class AffinitySpringTerm final : public ObjectiveTerm {
7158
void add_curvature(vtr::vector<APBlockId, double>& diagonal) const final;
7259

7360
private:
74-
double kernel_weight_(e_affinity_kind kind) const;
7561

7662
std::vector<AffinityGroup> groups_;
77-
double io_pair_attraction_weight_ = 0.;
7863
double pack_pattern_weight_ = 0.;
7964
vtr::vector<APBlockId, bool> moveable_; ///< Block mobility, precomputed (static per netlist).
8065
};

vpr/src/analytical_place/global_placement/electrostatic_density_utils.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ void dct_ii(const std::vector<double>& input,
6363
}
6464

6565
/**
66-
* @brief Apply the inverse of the unnormalized DCT-II through an inverse FFT.
66+
* @brief Apply an inverse DCT-II via an inverse FFT.
67+
*
68+
* NOTE: this returns exactly 2x the true DCT-II inverse. The factor is a single
69+
* frequency-independent scalar, absorbed by the density-weight normalization, so the
70+
* field shape and all force directions are unaffected.
6771
*/
6872
void idct_iii(const std::vector<double>& input,
6973
std::vector<double>& output,

vpr/src/analytical_place/global_placement/global_placer.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,8 @@ void update_timing_info_with_partial_placement(PreClusterTimingManager& pre_clus
380380
// For each AP pin, update the delay of the timing arc going through it.
381381
// The timing manager operates on the Atom netlist; however, by construction
382382
// of the AP netlist, every atom pin corresponds 1to1 to an AP pin.
383+
// Loop-invariant (depends only on the device center + delay model): hoisted out of the loop.
384+
const float delay_per_tile = get_delay_per_tile(place_delay_model);
383385
for (APPinId ap_pin_id : ap_netlist.pins()) {
384386
// Timing arcs are uniquely identified by the sink pin. Only update
385387
// timing for sink pins.
@@ -421,7 +423,7 @@ void update_timing_info_with_partial_placement(PreClusterTimingManager& pre_clus
421423
if (delay >= ROUTER_LOOKAHEAD_NO_PATH_SENTINEL) {
422424
int manhattan_dist = std::abs(driver_block_loc.x - sink_block_loc.x)
423425
+ std::abs(driver_block_loc.y - sink_block_loc.y);
424-
delay = manhattan_dist * get_delay_per_tile(place_delay_model);
426+
delay = manhattan_dist * delay_per_tile;
425427
}
426428

427429
// Get the atom pin associated with this AP pin (i.e. the one the AP
@@ -588,6 +590,6 @@ PartialPlacement SimPLGlobalPlacer::place() {
588590
*density_manager_,
589591
pre_cluster_timing_manager_);
590592

591-
// Return the placement from the final iteration.
593+
// Return the best placement found (lowest upper-bound HPWL), tracked across iterations.
592594
return best_p_placement;
593595
}

vpr/src/analytical_place/global_placement/global_placer.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
class APNetlist;
2323
class AnalyticalSolver;
2424
class LogicalModels;
25-
class PartialLegalizer;
2625
class PlaceDelayModel;
2726
class PreClusterTimingManager;
2827
class Prepacker;

vpr/src/analytical_place/global_placement/net_cohesion.cpp

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,14 @@ NetCohesion::NetCohesion(const APNetlist& ap_netlist,
3636
size_t device_grid_width,
3737
size_t device_grid_height,
3838
size_t device_grid_num_layers,
39-
double periphery_pair_weight,
4039
int log_verbosity)
4140
: ap_netlist_(ap_netlist)
4241
, density_manager_(density_manager)
4342
, device_grid_width_(device_grid_width)
4443
, device_grid_height_(device_grid_height)
4544
, device_grid_num_layers_(device_grid_num_layers)
46-
, periphery_pair_weight_(periphery_pair_weight)
4745
, log_verbosity_(log_verbosity)
48-
, periphery_pair_nets_(ap_netlist.nets().size(), false)
49-
, periphery_pair_damping_(ap_netlist.nets().size(), 1.) {}
46+
, periphery_pair_nets_(ap_netlist.nets().size(), false) {}
5047

5148
void NetCohesion::identify_boundary_confined_dims(const std::vector<PrimitiveVectorDim>& dimensions) {
5249
std::vector<bool> boundary_confined(dimensions.size(), false);
@@ -140,9 +137,7 @@ bool NetCohesion::block_has_boundary_mass(APBlockId blk_id,
140137

141138
void NetCohesion::update_periphery_pair_nets(const std::vector<PrimitiveVectorDim>& dimensions) {
142139
periphery_pair_nets_.resize(ap_netlist_.nets().size(), false);
143-
periphery_pair_damping_.resize(ap_netlist_.nets().size(), 1.);
144140
std::fill(periphery_pair_nets_.begin(), periphery_pair_nets_.end(), false);
145-
std::fill(periphery_pair_damping_.begin(), periphery_pair_damping_.end(), 1.);
146141
num_periphery_pair_nets_ = 0;
147142

148143
// Boundary mass is a property of the block, not of the net, so evaluate it
@@ -155,17 +150,6 @@ void NetCohesion::update_periphery_pair_nets(const std::vector<PrimitiveVectorDi
155150
boundary_blocks++;
156151
}
157152

158-
// Block degree, counting only pins attached to a net.
159-
vtr::vector<APBlockId, size_t> block_degree(ap_netlist_.blocks().size(), 0);
160-
for (APBlockId blk_id : ap_netlist_.blocks()) {
161-
for (APPinId pin_id : ap_netlist_.block_pins(blk_id)) {
162-
if (ap_netlist_.pin_net(pin_id).is_valid())
163-
block_degree[blk_id]++;
164-
}
165-
}
166-
167-
std::vector<size_t> selected_degrees;
168-
std::vector<APNetId> selected_ids;
169153
for (APNetId net_id : ap_netlist_.nets()) {
170154
if (ap_netlist_.net_is_ignored(net_id))
171155
continue;
@@ -182,30 +166,12 @@ void NetCohesion::update_periphery_pair_nets(const std::vector<PrimitiveVectorDi
182166
// partial legalization scatters scarce periphery resources, so a
183167
// seed-length gate misses exactly the nets that need cohesion.
184168
periphery_pair_nets_[net_id] = true;
185-
size_t degree = std::max(block_degree[first_blk_id], block_degree[second_blk_id]);
186-
// Parked as the raw degree; normalized against the median below.
187-
periphery_pair_damping_[net_id] = static_cast<double>(degree);
188-
selected_degrees.push_back(degree);
189-
selected_ids.push_back(net_id);
190-
}
191-
num_periphery_pair_nets_ = selected_ids.size();
192-
193-
// The reference degree is the median over the selected nets, so the damping
194-
// is derived per design rather than tuned to any one architecture. Each
195-
// net's degree is already parked in periphery_pair_damping_, so the median
196-
// reorders selected_degrees in place instead of copying it.
197-
if (!selected_degrees.empty()) {
198-
auto median = selected_degrees.begin() + selected_degrees.size() / 2;
199-
std::nth_element(selected_degrees.begin(), median, selected_degrees.end());
200-
double ref = std::max<double>(1., static_cast<double>(*median));
201-
for (APNetId net_id : selected_ids)
202-
periphery_pair_damping_[net_id] = std::min(1., ref / std::max(1., periphery_pair_damping_[net_id]));
169+
num_periphery_pair_nets_++;
203170
}
204171

205172
if (log_verbosity_ >= 1) {
206-
VTR_LOG("Nonlinear Nesterov periphery-pair cohesion: %zu boundary-mass blocks, %zu two-pin periphery nets, weight=%g.\n",
173+
VTR_LOG("Nonlinear Nesterov periphery-pair cohesion: %zu boundary-mass blocks, %zu two-pin periphery nets.\n",
207174
boundary_blocks,
208-
num_periphery_pair_nets_,
209-
periphery_pair_weight_);
175+
num_periphery_pair_nets_);
210176
}
211177
}

vpr/src/analytical_place/global_placement/net_cohesion.h

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@
66
* @brief Structural net-cohesion detection for the nonlinear Nesterov placer.
77
*
88
* The smooth wirelength objective lets two-pin nets between periphery-confined
9-
* blocks spread apart. Legalization then scatters those pairs, which downstream
10-
* packing and annealing cannot reliably repair. This module owns the detection
11-
* of that net class and the extra wirelength-weight multiplier that keeps its
12-
* endpoints together through the AP-to-APPack handoff; the placer applies the
13-
* multiplier inside its net-weight refresh.
9+
* blocks spread apart. This module owns the detection of that net class; the
10+
* placer uses the detected count to gate its pack-pattern affinity springs.
1411
*
1512
* The class is derived entirely from the parsed architecture: a resource
1613
* dimension is "boundary-confined" when the grid gives it capacity only near
@@ -31,8 +28,8 @@ class FlatPlacementDensityManager;
3128
*
3229
* Lifecycle per placement run: construct, call
3330
* @ref identify_boundary_confined_dims once the density dimensions are known,
34-
* then @ref update_periphery_pair_nets. Afterwards @ref net_multiplier yields
35-
* the cohesion weight factor for each net.
31+
* then @ref update_periphery_pair_nets. @ref num_periphery_pair_nets then
32+
* reports how many nets were flagged.
3633
*/
3734
class NetCohesion {
3835
public:
@@ -41,7 +38,6 @@ class NetCohesion {
4138
size_t device_grid_width,
4239
size_t device_grid_height,
4340
size_t device_grid_num_layers,
44-
double periphery_pair_weight,
4541
int log_verbosity);
4642

4743
/**
@@ -61,41 +57,22 @@ class NetCohesion {
6157

6258
/**
6359
* @brief Flag the two-pin nets whose endpoints both sit on boundary-confined
64-
* resources, and compute their degree damping.
60+
* resources.
6561
*/
6662
void update_periphery_pair_nets(const std::vector<PrimitiveVectorDim>& dimensions);
6763

6864
/// @brief Number of flagged periphery-pair nets (also gates pack-pattern affinity).
6965
size_t num_periphery_pair_nets() const { return num_periphery_pair_nets_; }
7066

71-
/**
72-
* @brief Cohesion weight multiplier for one net (1.0 when unflagged).
73-
*/
74-
double net_multiplier(APNetId net_id) const {
75-
if (static_cast<size_t>(net_id) >= periphery_pair_nets_.size() || !periphery_pair_nets_[net_id])
76-
return 1.;
77-
// Degree-normalized cohesion. A block on many two-pin periphery nets
78-
// accumulates the multiplier once per net, so its total pull scales with
79-
// its degree; a high-fanout periphery structure therefore drags far
80-
// harder than the simple pad-to-pad pair this class is meant to hold
81-
// together. Scaling by a reference degree bounds each block's total
82-
// contribution, which damps high-degree blocks without having to
83-
// identify them.
84-
return 1. + (periphery_pair_weight_ - 1.) * periphery_pair_damping_[net_id];
85-
}
86-
8767
private:
8868
const APNetlist& ap_netlist_;
8969
const FlatPlacementDensityManager& density_manager_;
9070
size_t device_grid_width_ = 0;
9171
size_t device_grid_height_ = 0;
9272
size_t device_grid_num_layers_ = 0;
93-
double periphery_pair_weight_ = 1.0;
9473
int log_verbosity_ = 0;
9574

9675
std::vector<bool> boundary_confined_dims_;
9776
vtr::vector<APNetId, bool> periphery_pair_nets_;
98-
/// @brief Per-net degree damping in [0,1]; 1 keeps the full weight.
99-
vtr::vector<APNetId, double> periphery_pair_damping_;
10077
size_t num_periphery_pair_nets_ = 0;
10178
};

0 commit comments

Comments
 (0)