Skip to content

Commit db86bbf

Browse files
authored
Merge pull request #3224 from AlexandreSinger/feature-appack-placer-fallback
[APPack] Initial Placement Fallback
2 parents 2bda76c + 9cadabc commit db86bbf

File tree

2 files changed

+105
-38
lines changed

2 files changed

+105
-38
lines changed

vpr/src/place/initial_placement.cpp

Lines changed: 104 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -571,12 +571,42 @@ static std::vector<ClusterBlockId> find_centroid_loc(const t_pl_macro& pl_macro,
571571
return connected_blocks_to_update;
572572
}
573573

574+
/**
575+
* @brief Helper method for getting the flat position of an atom relative to a
576+
* given offset.
577+
*
578+
* This method is useful for chained blocks where an atom may be a member of a
579+
* chain with the given offset. This gives the atom's position relative to the
580+
* head macro's tile location.
581+
*/
582+
static t_flat_pl_loc get_atom_relative_flat_loc(AtomBlockId atom_blk_id,
583+
const t_pl_offset& offset,
584+
const FlatPlacementInfo& flat_placement_info,
585+
const DeviceGrid& device_grid) {
586+
// Get the flat location of the atom and the offset.
587+
t_flat_pl_loc atom_pos = flat_placement_info.get_pos(atom_blk_id);
588+
t_flat_pl_loc flat_offset = t_flat_pl_loc((float)offset.x,
589+
(float)offset.y,
590+
(float)offset.layer);
591+
// Get the position of the head macro of the chain that this atom is a part of.
592+
atom_pos -= flat_offset;
593+
594+
// This may put the atom off device (due to the flat placement not being fully
595+
// legal), so we clamp this to be within the device.
596+
atom_pos.x = std::clamp(atom_pos.x, 0.0f, (float)device_grid.width() - 0.001f);
597+
atom_pos.y = std::clamp(atom_pos.y, 0.0f, (float)device_grid.height() - 0.001f);
598+
atom_pos.layer = std::clamp(atom_pos.layer, 0.0f, (float)device_grid.get_num_layers() - 0.001f);
599+
600+
return atom_pos;
601+
}
602+
574603
// TODO: Should this return the unplaced_blocks_to_update_their_score?
575604
static t_flat_pl_loc find_centroid_loc_from_flat_placement(const t_pl_macro& pl_macro,
576605
const FlatPlacementInfo& flat_placement_info) {
577606
// Use the flat placement to compute the centroid of the given macro.
578607
// TODO: Instead of averaging, maybe use MODE (most frequently placed location).
579-
float acc_weight = 0.f;
608+
const DeviceGrid& device_grid = g_vpr_ctx.device().grid;
609+
unsigned acc_weight = 0;
580610
t_flat_pl_loc centroid({0.0f, 0.0f, 0.0f});
581611
for (const t_pl_macro_member& member : pl_macro.members) {
582612
const auto& cluster_atoms = g_vpr_ctx.clustering().atoms_lookup[member.blk_index];
@@ -585,19 +615,19 @@ static t_flat_pl_loc find_centroid_loc_from_flat_placement(const t_pl_macro& pl_
585615
VTR_ASSERT(flat_placement_info.blk_x_pos[atom_blk_id] != FlatPlacementInfo::UNDEFINED_POS && flat_placement_info.blk_y_pos[atom_blk_id] != FlatPlacementInfo::UNDEFINED_POS && flat_placement_info.blk_layer[atom_blk_id] != FlatPlacementInfo::UNDEFINED_POS && flat_placement_info.blk_sub_tile[atom_blk_id] != FlatPlacementInfo::UNDEFINED_SUB_TILE);
586616

587617
// Accumulate the x, y, layer, and sub_tile for each atom in each
588-
// member of the macro. Remove the offset so the centroid would be
589-
// where the head macro should be placed to put the members in the
590-
// correct place.
591-
t_flat_pl_loc cluster_offset({(float)member.offset.x,
592-
(float)member.offset.y,
593-
(float)member.offset.layer});
594-
centroid += flat_placement_info.get_pos(atom_blk_id);
595-
centroid -= cluster_offset;
618+
// member of the macro. The position should be relative to the head
619+
// macro's position such that the centroid is where all blocks think
620+
// the head macro should be.
621+
t_flat_pl_loc atom_pos = get_atom_relative_flat_loc(atom_blk_id,
622+
member.offset,
623+
flat_placement_info,
624+
device_grid);
625+
centroid += atom_pos;
596626
acc_weight++;
597627
}
598628
}
599-
if (acc_weight > 0.f) {
600-
centroid /= acc_weight;
629+
if (acc_weight > 0) {
630+
centroid /= static_cast<float>(acc_weight);
601631
}
602632

603633
// If the root cluster is constrained, project the centroid onto its
@@ -1532,26 +1562,28 @@ bool place_one_block(const ClusterBlockId blk_id,
15321562
static inline float get_flat_variance(const t_pl_macro& macro,
15331563
const FlatPlacementInfo& flat_placement_info) {
15341564

1565+
const DeviceGrid& device_grid = g_vpr_ctx.device().grid;
1566+
15351567
// Find the flat centroid location of this macro. Then find the grid location
15361568
// that this would be.
15371569
t_flat_pl_loc centroid_flat_loc = find_centroid_loc_from_flat_placement(macro, flat_placement_info);
15381570
t_physical_tile_loc centroid_grid_loc(centroid_flat_loc.x,
15391571
centroid_flat_loc.y,
15401572
centroid_flat_loc.layer);
1573+
VTR_ASSERT(is_loc_on_chip(centroid_grid_loc));
15411574

15421575
// Compute the variance.
1543-
float num_atoms = 0;
1576+
unsigned num_atoms = 0;
15441577
float variance = 0.0f;
15451578
for (const t_pl_macro_member& member : macro.members) {
15461579
const auto& cluster_atoms = g_vpr_ctx.clustering().atoms_lookup[member.blk_index];
15471580
for (AtomBlockId atom_blk_id : cluster_atoms) {
15481581
// Get the atom position, offset by the member offset. This translates
15491582
// all atoms to be as if they are in the head position of the macro.
1550-
t_flat_pl_loc atom_pos = flat_placement_info.get_pos(atom_blk_id);
1551-
t_flat_pl_loc cluster_offset({(float)member.offset.x,
1552-
(float)member.offset.y,
1553-
(float)member.offset.layer});
1554-
atom_pos -= cluster_offset;
1583+
t_flat_pl_loc atom_pos = get_atom_relative_flat_loc(atom_blk_id,
1584+
member.offset,
1585+
flat_placement_info,
1586+
device_grid);
15551587

15561588
// Get the amount this atom needs to be displaced in order to be
15571589
// within the same tile as the centroid.
@@ -1564,8 +1596,8 @@ static inline float get_flat_variance(const t_pl_macro& macro,
15641596
num_atoms++;
15651597
}
15661598
}
1567-
if (num_atoms > 0.f) {
1568-
variance /= num_atoms;
1599+
if (num_atoms > 0) {
1600+
variance /= static_cast<float>(num_atoms);
15691601
}
15701602
return variance;
15711603
}
@@ -1676,8 +1708,9 @@ static inline std::vector<ClusterBlockId> get_sorted_clusters_to_place(
16761708
// first.
16771709
// TODO: The cluster constrained area can be incorperated into the cost
16781710
// somehow.
1679-
if (is_cluster_constrained(blk_id)) {
1680-
const PartitionRegion& pr = cluster_constraints[blk_id];
1711+
ClusterBlockId macro_head_blk = pl_macro.members[0].blk_index;
1712+
if (is_cluster_constrained(macro_head_blk)) {
1713+
const PartitionRegion& pr = cluster_constraints[macro_head_blk];
16811714
float area = 0.0f;
16821715
for (const Region& region : pr.get_regions()) {
16831716
const vtr::Rect<int> region_rect = region.get_rect();
@@ -1705,6 +1738,7 @@ static inline std::vector<ClusterBlockId> get_sorted_clusters_to_place(
17051738
/**
17061739
* @brief Tries to place all of the given clusters as closed to their flat
17071740
* placement as possible (minimum displacement from flat placement).
1741+
* Returns false if any clusters could not be placed.
17081742
*
17091743
* This function will place clusters in passes. In the first pass, it will try
17101744
* to place clusters exactly where their global placement is (according to the
@@ -1713,7 +1747,7 @@ static inline std::vector<ClusterBlockId> get_sorted_clusters_to_place(
17131747
* Subsequent passes will then try to place clusters at exponentially farther
17141748
* distances.
17151749
*/
1716-
static inline void place_blocks_min_displacement(std::vector<ClusterBlockId>& clusters_to_place,
1750+
static inline bool place_blocks_min_displacement(std::vector<ClusterBlockId>& clusters_to_place,
17171751
enum e_pad_loc_type pad_loc_type,
17181752
BlkLocRegistry& blk_loc_registry,
17191753
const PlaceMacros& place_macros,
@@ -1841,28 +1875,30 @@ static inline void place_blocks_min_displacement(std::vector<ClusterBlockId>& cl
18411875
if (clusters_to_place.size() > 0) {
18421876
VTR_LOG("Unable to place all clusters.\n");
18431877
VTR_LOG("Clusters left unplaced:\n");
1878+
// TODO: Increase the log verbosity of this.
18441879
for (ClusterBlockId blk_id : clusters_to_place) {
18451880
VTR_LOG("\t%s\n", cluster_netlist.block_name(blk_id).c_str());
18461881
}
18471882
}
18481883

1849-
// Check if anything has not been placed, if so just crash for now.
1850-
// TODO: Should fall back on the original initial placer. Unless there is a
1851-
// bug in the code above, it could be that it is challenging to place
1852-
// for this circuit.
1853-
VTR_ASSERT(clusters_to_place.size() == 0);
1884+
// Check if anything has not been placed, if so, signal to the calling function.
1885+
if (clusters_to_place.size() > 0)
1886+
return false;
1887+
1888+
return true;
18541889
}
18551890

18561891
/**
18571892
* @brief Places all blocks in the clustered netlist as close to the global
1858-
* placement produced by the AP flow.
1893+
* placement produced by the AP flow. Returns false if any blocks could
1894+
* not be placed.
18591895
*
18601896
* This function places the blocks in stages. The goal of this stage-based
18611897
* approach is to place clusters which are challenging to place first. Within
18621898
* each stage, the clusters are ordered based on heuristics such that the most
18631899
* impactful clusters get first dibs on placement.
18641900
*/
1865-
static inline void place_all_blocks_ap(enum e_pad_loc_type pad_loc_type,
1901+
static inline bool place_all_blocks_ap(enum e_pad_loc_type pad_loc_type,
18661902
BlkLocRegistry& blk_loc_registry,
18671903
const PlaceMacros& place_macros,
18681904
const FlatPlacementInfo& flat_placement_info) {
@@ -1892,13 +1928,17 @@ static inline void place_all_blocks_ap(enum e_pad_loc_type pad_loc_type,
18921928

18931929
if (constrained_clusters.size() > 0) {
18941930
VTR_LOG("Placing constrained clusters...\n");
1895-
place_blocks_min_displacement(constrained_clusters,
1931+
bool all_clusters_placed = place_blocks_min_displacement(constrained_clusters,
18961932
pad_loc_type,
18971933
blk_loc_registry,
18981934
place_macros,
18991935
cluster_netlist,
19001936
flat_placement_info);
19011937
VTR_LOG("\n");
1938+
if (!all_clusters_placed) {
1939+
VTR_LOG("Could not place all constrained clusters, falling back on the non-AP initial placement.\n");
1940+
return false;
1941+
}
19021942
}
19031943

19041944
// 2. Get all of the large macros and place them next. Large macros have a
@@ -1924,13 +1964,17 @@ static inline void place_all_blocks_ap(enum e_pad_loc_type pad_loc_type,
19241964

19251965
if (large_macro_clusters.size() > 0) {
19261966
VTR_LOG("Placing clusters that are part of larger macros...\n");
1927-
place_blocks_min_displacement(large_macro_clusters,
1967+
bool all_clusters_placed = place_blocks_min_displacement(large_macro_clusters,
19281968
pad_loc_type,
19291969
blk_loc_registry,
19301970
place_macros,
19311971
cluster_netlist,
19321972
flat_placement_info);
19331973
VTR_LOG("\n");
1974+
if (!all_clusters_placed) {
1975+
VTR_LOG("Could not place all large macros, falling back on the non-AP initial placement.\n");
1976+
return false;
1977+
}
19341978
}
19351979

19361980
// 3. Place the rest of the clusters. These clusters will be unconstrained
@@ -1948,14 +1992,20 @@ static inline void place_all_blocks_ap(enum e_pad_loc_type pad_loc_type,
19481992

19491993
if (clusters_to_place.size() > 0) {
19501994
VTR_LOG("Placing general clusters...\n");
1951-
place_blocks_min_displacement(clusters_to_place,
1995+
bool all_clusters_placed = place_blocks_min_displacement(clusters_to_place,
19521996
pad_loc_type,
19531997
blk_loc_registry,
19541998
place_macros,
19551999
cluster_netlist,
19562000
flat_placement_info);
19572001
VTR_LOG("\n");
2002+
if (!all_clusters_placed) {
2003+
VTR_LOG("Could not place all clusters, falling back on the non-AP initial placement.\n");
2004+
return false;
2005+
}
19582006
}
2007+
2008+
return true;
19592009
}
19602010

19612011
void initial_placement(const t_placer_opts& placer_opts,
@@ -1991,13 +2041,29 @@ void initial_placement(const t_placer_opts& placer_opts,
19912041
}
19922042

19932043
//Place all blocks
2044+
bool all_blocks_placed = false;
2045+
2046+
// First try to place all of the blocks using AP
19942047
if (flat_placement_info.valid) {
1995-
place_all_blocks_ap(placer_opts.pad_loc_type,
1996-
blk_loc_registry,
1997-
place_macros,
1998-
flat_placement_info);
1999-
} else {
2000-
//Assign scores to blocks and placement macros according to how difficult they are to place
2048+
all_blocks_placed = place_all_blocks_ap(placer_opts.pad_loc_type,
2049+
blk_loc_registry,
2050+
place_macros,
2051+
flat_placement_info);
2052+
2053+
// If AP failed to place all of the blocks, reset the placement solution
2054+
// so we can fall back on the original initial placement algorithm.
2055+
if (!all_blocks_placed) {
2056+
blk_loc_registry.clear_all_grid_locs();
2057+
if (strlen(constraints_file) != 0) {
2058+
read_constraints(constraints_file, blk_loc_registry);
2059+
}
2060+
}
2061+
}
2062+
2063+
// If all of the blocks have not been placed (i.e. AP is turned off or
2064+
// is disabled), try to place all of the clusters using heuristics.
2065+
if (!all_blocks_placed) {
2066+
// Assign scores to blocks and placement macros according to how difficult they are to place
20012067
vtr::vector<ClusterBlockId, t_block_score> block_scores = assign_block_scores(place_macros);
20022068

20032069
place_all_blocks(placer_opts, block_scores, placer_opts.pad_loc_type,

vtr_flow/parse/qor_config/qor_ap_fixed_chan_width.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ total_runtime;vpr.out;The entire flow of VPR took (.*) seconds
3131
num_clb;vpr.out;Netlist clb blocks:\s*(\d+)
3232
num_lab;vpr.out;Netlist LAB blocks:\s*(\d+)
3333

34+
num_pre_packed_blocks;vpr.out;\s+total blocks:\s*(\d+),.*

0 commit comments

Comments
 (0)