Skip to content

Commit

Permalink
[AP] Partial Legalizer
Browse files Browse the repository at this point in the history
This adds the Patial Legalizer block into VPR. A Partial Legalizer takes
a partial placement (which likely has many overlapping blocks and is
very illegal with blocks in the wrong tiles) and creates a more legal
partial placement. These are often called spreaders since their main
task is to spread blocks away from each other (the solver tends to put
blocks on top of each other).

Added a multi-commodity flow-based spreading partial legalizer based on
the work by Darav et al. This algorithm was modified to work within the
VPR infrastructure on any hypothetical architecture which can be
expressed in VPR.
  • Loading branch information
AlexandreSinger committed Nov 12, 2024
1 parent 5a062ba commit 34200ac
Show file tree
Hide file tree
Showing 9 changed files with 2,133 additions and 23 deletions.
11 changes: 9 additions & 2 deletions vpr/src/analytical_place/analytical_placement_flow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "full_legalizer.h"
#include "gen_ap_netlist_from_atoms.h"
#include "globals.h"
#include "partial_legalizer.h"
#include "partial_placement.h"
#include "prepack.h"
#include "user_place_constraints.h"
Expand Down Expand Up @@ -53,6 +54,7 @@ static void print_ap_netlist_stats(const APNetlist& netlist) {
VTR_LOG("\t\tAverage Fanout: %.2f\n", average_fanout);
VTR_LOG("\t\tHighest Fanout: %zu\n", highest_fanout);
VTR_LOG("\tPins: %zu\n", netlist.pins().size());
VTR_LOG("\n");
}

void run_analytical_placement_flow(t_vpr_setup& vpr_setup) {
Expand All @@ -77,11 +79,16 @@ void run_analytical_placement_flow(t_vpr_setup& vpr_setup) {
print_ap_netlist_stats(ap_netlist);

// Run the Global Placer
// For now, just runs the solver.
// For now, just runs the solver and partial legalizer 10 times arbitrarily.
PartialPlacement p_placement(ap_netlist);
std::unique_ptr<AnalyticalSolver> solver = make_analytical_solver(e_analytical_solver::QP_HYBRID,
ap_netlist);
solver->solve(0, p_placement);
std::unique_ptr<PartialLegalizer> legalizer = make_partial_legalizer(e_partial_legalizer::FLOW_BASED,
ap_netlist);
for (size_t i = 0; i < 10; i++) {
solver->solve(i, p_placement);
legalizer->legalize(p_placement);
}

// Verify that the partial placement is valid before running the full
// legalizer.
Expand Down
37 changes: 24 additions & 13 deletions vpr/src/analytical_place/full_legalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
* @file
* @author Alex Singer
* @date September 2024
* @brief Implements the full legalizer in the AP flow.
* @brief Implements the full legalizer in the AP flow. The Full Legalizer
* takes a partial placement and fully legalizes it. This involves
* creating legal clusters and placing them into valid tile sites.
*/

#include "full_legalizer.h"
Expand Down Expand Up @@ -33,6 +35,7 @@
#include "vpr_error.h"
#include "vpr_types.h"
#include "vtr_assert.h"
#include "vtr_geometry.h"
#include "vtr_ndmatrix.h"
#include "vtr_strong_id.h"
#include "vtr_time.h"
Expand Down Expand Up @@ -126,9 +129,8 @@ class APClusterPlacer {
const t_physical_tile_loc& tile_loc,
int sub_tile) {
const DeviceContext& device_ctx = g_vpr_ctx.device();
// FIXME: THIS MUST TAKE INTO ACCOUNT THE CONSTRAINTS AS WELL!!!
// - Right now it is just implied.
// - Will work but is unstable.
const FloorplanningContext& floorplanning_ctx = g_vpr_ctx.floorplanning();
const ClusteringContext& cluster_ctx = g_vpr_ctx.clustering();
const auto& block_locs = g_vpr_ctx.placement().block_locs();
auto& blk_loc_registry = g_vpr_ctx.mutable_placement().mutable_blk_loc_registry();
VTR_ASSERT(!is_block_placed(clb_blk_id, block_locs) && "Block already placed. Is this intentional?");
Expand All @@ -141,11 +143,24 @@ class APClusterPlacer {
if (device_ctx.grid.get_physical_type(tile_loc)->sub_tiles.size() == 0)
return false;
VTR_ASSERT(sub_tile >= 0 && sub_tile < device_ctx.grid.get_physical_type(tile_loc)->capacity);
// FIXME: Do this better.
// - May need to try all the sub-tiles in a location.
// - https://github.com/AlexandreSinger/vtr-verilog-to-routing/blob/feature-analytical-placer/vpr/src/place/initial_placement.cpp#L755
to_loc.sub_tile = sub_tile;
return try_place_macro(pl_macro, to_loc, blk_loc_registry);
// Check if this cluster is constrained and this location is legal.
if (is_cluster_constrained(clb_blk_id)) {
const auto& cluster_constraints = floorplanning_ctx.cluster_constraints;
if (cluster_constraints[clb_blk_id].is_loc_in_part_reg(to_loc))
return false;
}
// If the location is legal, try to exhaustively place it at this tile
// location. This should try all sub_tiles.
PartitionRegion pr;
vtr::Rect<int> rect(tile_loc.x, tile_loc.y, tile_loc.x, tile_loc.y);
pr.add_to_part_region(Region(rect, to_loc.layer));
const ClusteredNetlist& clb_nlist = cluster_ctx.clb_nlist;
t_logical_block_type_ptr block_type = clb_nlist.block_type(clb_blk_id);
enum e_pad_loc_type pad_loc_type = g_vpr_ctx.device().pad_loc_type;
// FIXME: This currently ignores the sub_tile. Was running into issues
// with trying to force clusters to specific sub_tiles.
return try_place_macro_exhaustively(pl_macro, pr, block_type,
pad_loc_type, blk_loc_registry);
}

// This is not the best way of doing things, but its the simplest. Given a
Expand Down Expand Up @@ -356,10 +371,6 @@ void FullLegalizer::place_clusters(const ClusteredNetlist& clb_nlist,
bool placed = ap_cluster_placer.place_cluster(cluster_blk_id, tile_loc, blk_sub_tile);
if (placed)
continue;
// FIXME: Should now try all sub-tiles at this tile location.
// - May need to try all the sub-tiles in a location.
// - however this may need to be done after.
// - https://github.com/AlexandreSinger/vtr-verilog-to-routing/blob/feature-analytical-placer/vpr/src/place/initial_placement.cpp#L755

// Add to list of unplaced clusters.
unplaced_clusters.push_back(cluster_blk_id);
Expand Down
Loading

0 comments on commit 34200ac

Please sign in to comment.