Skip to content

Commit 8824298

Browse files
Merge pull request verilog-to-routing#3131 from AlexandreSinger/feature-ap-initial-placer
[AP][IP] Split Initial Placement Into Stages
2 parents b7581d1 + 550d6de commit 8824298

File tree

1 file changed

+145
-15
lines changed

1 file changed

+145
-15
lines changed

vpr/src/place/initial_placement.cpp

Lines changed: 145 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <limits>
3030
#include <optional>
3131
#include <queue>
32+
#include <vector>
3233

3334
#ifdef VERBOSE
3435
void print_clb_placement(const char* fname);
@@ -1628,27 +1629,20 @@ static void print_ap_initial_placer_status(unsigned iteration,
16281629
}
16291630

16301631
/**
1631-
* @brief Places all blocks in the clustered netlist as close to the global
1632-
* placement produced by the AP flow.
1633-
*
1634-
* This function will place clusters in passes. In the first pass, it will try
1635-
* to place clusters exactly where their global placement is (according to the
1636-
* atoms contained in the cluster). In the second pass, all unplaced clusters
1637-
* will try to be placed within 1 tile of where they wanted to be placed.
1638-
* Subsequent passes will then try to place clusters at exponentially farther
1639-
* distances.
1632+
* @brief Collects unplaced clusters and sorts such that clusters which should
1633+
* be placed first appear early in the list.
16401634
*
16411635
* The clusters are sorted based on how many clusters are in the macro that
16421636
* contains this cluster and the standard deviation of the placement of atoms
16431637
* within the cluster. Large macros with low standard deviation will be placed
16441638
* first.
16451639
*/
1646-
static inline void place_all_blocks_ap(enum e_pad_loc_type pad_loc_type,
1647-
BlkLocRegistry& blk_loc_registry,
1648-
const PlaceMacros& place_macros,
1649-
const FlatPlacementInfo& flat_placement_info) {
1650-
const ClusteredNetlist& cluster_netlist = g_vpr_ctx.clustering().clb_nlist;
1651-
const DeviceGrid& device_grid = g_vpr_ctx.device().grid;
1640+
static inline std::vector<ClusterBlockId> get_sorted_clusters_to_place(
1641+
BlkLocRegistry& blk_loc_registry,
1642+
const PlaceMacros& place_macros,
1643+
const ClusteredNetlist& cluster_netlist,
1644+
const FlatPlacementInfo& flat_placement_info) {
1645+
16521646
const auto& cluster_constraints = g_vpr_ctx.floorplanning().cluster_constraints;
16531647

16541648
// Create a list of clusters to place.
@@ -1728,6 +1722,29 @@ static inline void place_all_blocks_ap(enum e_pad_loc_type pad_loc_type,
17281722
return cluster_score[lhs] > cluster_score[rhs];
17291723
});
17301724

1725+
return clusters_to_place;
1726+
}
1727+
1728+
/**
1729+
* @brief Tries to place all of the given clusters as closed to their flat
1730+
* placement as possible (minimum displacement from flat placement).
1731+
*
1732+
* This function will place clusters in passes. In the first pass, it will try
1733+
* to place clusters exactly where their global placement is (according to the
1734+
* atoms contained in the cluster). In the second pass, all unplaced clusters
1735+
* will try to be placed within 1 tile of where they wanted to be placed.
1736+
* Subsequent passes will then try to place clusters at exponentially farther
1737+
* distances.
1738+
*/
1739+
static inline void place_blocks_min_displacement(std::vector<ClusterBlockId>& clusters_to_place,
1740+
enum e_pad_loc_type pad_loc_type,
1741+
BlkLocRegistry& blk_loc_registry,
1742+
const PlaceMacros& place_macros,
1743+
const ClusteredNetlist& cluster_netlist,
1744+
const FlatPlacementInfo& flat_placement_info) {
1745+
1746+
const DeviceGrid& device_grid = g_vpr_ctx.device().grid;
1747+
17311748
// Compute the max L1 distance on the device. If we cannot find a location
17321749
// to place a cluster within this distance, then no legal location exists.
17331750
float max_distance_on_device = device_grid.width() + device_grid.height();
@@ -1844,13 +1861,126 @@ static inline void place_all_blocks_ap(enum e_pad_loc_type pad_loc_type,
18441861
iter++;
18451862
}
18461863

1864+
if (clusters_to_place.size() > 0) {
1865+
VTR_LOG("Unable to place all clusters.\n");
1866+
VTR_LOG("Clusters left unplaced:\n");
1867+
for (ClusterBlockId blk_id : clusters_to_place) {
1868+
VTR_LOG("\t%s\n", cluster_netlist.block_name(blk_id).c_str());
1869+
}
1870+
}
1871+
18471872
// Check if anything has not been placed, if so just crash for now.
18481873
// TODO: Should fall back on the original initial placer. Unless there is a
18491874
// bug in the code above, it could be that it is challenging to place
18501875
// for this circuit.
18511876
VTR_ASSERT(clusters_to_place.size() == 0);
18521877
}
18531878

1879+
/**
1880+
* @brief Places all blocks in the clustered netlist as close to the global
1881+
* placement produced by the AP flow.
1882+
*
1883+
* This function places the blocks in stages. The goal of this stage-based
1884+
* approach is to place clusters which are challenging to place first. Within
1885+
* each stage, the clusters are ordered based on heuristics such that the most
1886+
* impactful clusters get first dibs on placement.
1887+
*/
1888+
static inline void place_all_blocks_ap(enum e_pad_loc_type pad_loc_type,
1889+
BlkLocRegistry& blk_loc_registry,
1890+
const PlaceMacros& place_macros,
1891+
const FlatPlacementInfo& flat_placement_info) {
1892+
1893+
const ClusteredNetlist& cluster_netlist = g_vpr_ctx.clustering().clb_nlist;
1894+
1895+
// Get a list of clusters to place, sorted based on different heuristics
1896+
// to try to give more important clusters first dibs on the placement.
1897+
std::vector<ClusterBlockId> sorted_cluster_list = get_sorted_clusters_to_place(blk_loc_registry,
1898+
place_macros,
1899+
cluster_netlist,
1900+
flat_placement_info);
1901+
1902+
// 1: Get the constrained clusters and place them first. For now, we place
1903+
// constrained clusters first to prevent other clusters from taking their
1904+
// spot if they are constrained to one and only one site.
1905+
// TODO: This gives clusters with region constraints VIP access to the
1906+
// placement. This may not give the best results. This should be
1907+
// investigated more once region constraints are more supported in the
1908+
// AP flow.
1909+
std::vector<ClusterBlockId> constrained_clusters;
1910+
constrained_clusters.reserve(sorted_cluster_list.size());
1911+
for (ClusterBlockId blk_id : sorted_cluster_list) {
1912+
if (is_cluster_constrained(blk_id))
1913+
constrained_clusters.push_back(blk_id);
1914+
}
1915+
1916+
if (constrained_clusters.size() > 0) {
1917+
VTR_LOG("Placing constrained clusters...\n");
1918+
place_blocks_min_displacement(constrained_clusters,
1919+
pad_loc_type,
1920+
blk_loc_registry,
1921+
place_macros,
1922+
cluster_netlist,
1923+
flat_placement_info);
1924+
VTR_LOG("\n");
1925+
}
1926+
1927+
// 2. Get all of the large macros and place them next. Large macros have a
1928+
// hard time finding a place to go since they take up so much space. They
1929+
// also can have a larger impact on the quality of the placement, so we
1930+
// give them dibs on placement early.
1931+
std::vector<ClusterBlockId> large_macro_clusters;
1932+
large_macro_clusters.reserve(sorted_cluster_list.size());
1933+
for (ClusterBlockId blk_id : sorted_cluster_list) {
1934+
// If this block has been placed, skip it.
1935+
if (is_block_placed(blk_id, blk_loc_registry.block_locs()))
1936+
continue;
1937+
1938+
// Get the size of the macro this block is a part of.
1939+
t_pl_macro pl_macro = get_or_create_macro(blk_id, place_macros);
1940+
size_t macro_size = pl_macro.members.size();
1941+
if (macro_size > 1) {
1942+
// If the size of the macro is larger than 1 (there is more than
1943+
// one cluster in this macro) add to the list.
1944+
large_macro_clusters.push_back(blk_id);
1945+
}
1946+
}
1947+
1948+
if (large_macro_clusters.size() > 0) {
1949+
VTR_LOG("Placing clusters that are part of larger macros...\n");
1950+
place_blocks_min_displacement(large_macro_clusters,
1951+
pad_loc_type,
1952+
blk_loc_registry,
1953+
place_macros,
1954+
cluster_netlist,
1955+
flat_placement_info);
1956+
VTR_LOG("\n");
1957+
}
1958+
1959+
// 3. Place the rest of the clusters. These clusters will be unconstrained
1960+
// and be of small size; so they are more free to fill in the gaps left
1961+
// behind.
1962+
std::vector<ClusterBlockId> clusters_to_place;
1963+
clusters_to_place.reserve(sorted_cluster_list.size());
1964+
for (ClusterBlockId blk_id : sorted_cluster_list) {
1965+
// If this block has been placed, skip it.
1966+
if (is_block_placed(blk_id, blk_loc_registry.block_locs()))
1967+
continue;
1968+
1969+
clusters_to_place.push_back(blk_id);
1970+
}
1971+
1972+
if (clusters_to_place.size() > 0) {
1973+
VTR_LOG("Placing general clusters...\n");
1974+
place_blocks_min_displacement(clusters_to_place,
1975+
pad_loc_type,
1976+
blk_loc_registry,
1977+
place_macros,
1978+
cluster_netlist,
1979+
flat_placement_info);
1980+
VTR_LOG("\n");
1981+
}
1982+
}
1983+
18541984
void initial_placement(const t_placer_opts& placer_opts,
18551985
const char* constraints_file,
18561986
const t_noc_opts& noc_opts,

0 commit comments

Comments
 (0)