-
Notifications
You must be signed in to change notification settings - Fork 414
[AP] Added APPack to the AP Flow as a Full Legalizer #2892
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/** | ||
* @file | ||
* @author Alex Singer | ||
* @date February 2025 | ||
* @brief Enumerations used by the Analytical Placement Flow. | ||
*/ | ||
|
||
#pragma once | ||
|
||
/** | ||
* @brief The type of a Full Legalizer. | ||
* | ||
* The Analytical Placement flow may implement different Full Legalizers. This | ||
* enum can select between these different Full Legalizers. | ||
*/ | ||
enum class e_ap_full_legalizer { | ||
Naive, ///< The Naive Full Legalizer, which clusters atoms placed in the same tile and tries to place them in that tile according to the flat placement. | ||
APPack ///< The APPack Full Legalizer, which uses the flat placement to improve the Packer and Placer. | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,9 +10,13 @@ | |
#include "full_legalizer.h" | ||
|
||
#include <list> | ||
#include <memory> | ||
#include <unordered_set> | ||
#include <vector> | ||
|
||
#include "FlatPlacementInfo.h" | ||
#include "ap_flow_enums.h" | ||
#include "device_grid.h" | ||
#include "partial_placement.h" | ||
#include "ShowSetup.h" | ||
#include "ap_netlist_fwd.h" | ||
|
@@ -25,6 +29,7 @@ | |
#include "logic_types.h" | ||
#include "pack.h" | ||
#include "physical_types.h" | ||
#include "place.h" | ||
#include "place_and_route.h" | ||
#include "place_constraints.h" | ||
#include "place_macro.h" | ||
|
@@ -42,6 +47,38 @@ | |
#include "vtr_time.h" | ||
#include "vtr_vector.h" | ||
|
||
|
||
std::unique_ptr<FullLegalizer> make_full_legalizer(e_ap_full_legalizer full_legalizer_type, | ||
const APNetlist& ap_netlist, | ||
const AtomNetlist& atom_netlist, | ||
const Prepacker& prepacker, | ||
t_vpr_setup& vpr_setup, | ||
const t_arch& arch, | ||
const DeviceGrid& device_grid, | ||
const std::vector<t_logical_block_type>& logical_block_types) { | ||
switch (full_legalizer_type) { | ||
case e_ap_full_legalizer::Naive: | ||
return std::make_unique<NaiveFullLegalizer>(ap_netlist, | ||
atom_netlist, | ||
prepacker, | ||
vpr_setup, | ||
arch, | ||
device_grid, | ||
logical_block_types); | ||
case e_ap_full_legalizer::APPack: | ||
return std::make_unique<APPack>(ap_netlist, | ||
atom_netlist, | ||
prepacker, | ||
vpr_setup, | ||
arch, | ||
device_grid, | ||
logical_block_types); | ||
default: | ||
VPR_FATAL_ERROR(VPR_ERROR_AP, | ||
"Unrecognized full legalizer type"); | ||
} | ||
} | ||
|
||
namespace { | ||
|
||
/// @brief A unique ID for each root tile on the device. | ||
|
@@ -239,24 +276,24 @@ static LegalizationClusterId create_new_cluster(PackMoleculeId seed_molecule_id, | |
return LegalizationClusterId(); | ||
} | ||
|
||
void FullLegalizer::create_clusters(const PartialPlacement& p_placement) { | ||
void NaiveFullLegalizer::create_clusters(const PartialPlacement& p_placement) { | ||
// PACKING: | ||
// Initialize the cluster legalizer (Packing) | ||
// FIXME: The legalization strategy is currently set to full. Should handle | ||
// this better to make it faster. | ||
t_pack_high_fanout_thresholds high_fanout_thresholds(packer_opts_.high_fanout_threshold); | ||
t_pack_high_fanout_thresholds high_fanout_thresholds(vpr_setup_.PackerOpts.high_fanout_threshold); | ||
ClusterLegalizer cluster_legalizer(atom_netlist_, | ||
prepacker_, | ||
logical_block_types_, | ||
lb_type_rr_graphs_, | ||
user_models_, | ||
library_models_, | ||
packer_opts_.target_external_pin_util, | ||
vpr_setup_.PackerRRGraph, | ||
arch_.models, | ||
arch_.model_library, | ||
vpr_setup_.PackerOpts.target_external_pin_util, | ||
high_fanout_thresholds, | ||
ClusterLegalizationStrategy::FULL, | ||
packer_opts_.enable_pin_feasibility_filter, | ||
packer_opts_.feasible_block_array_size, | ||
packer_opts_.pack_verbosity); | ||
vpr_setup_.PackerOpts.enable_pin_feasibility_filter, | ||
vpr_setup_.PackerOpts.feasible_block_array_size, | ||
vpr_setup_.PackerOpts.pack_verbosity); | ||
// Create clusters for each tile. | ||
// Start by giving each root tile a unique ID. | ||
size_t grid_width = device_grid_.width(); | ||
|
@@ -330,24 +367,24 @@ void FullLegalizer::create_clusters(const PartialPlacement& p_placement) { | |
|
||
// Check and output the clustering. | ||
std::unordered_set<AtomNetId> is_clock = alloc_and_load_is_clock(); | ||
check_and_output_clustering(cluster_legalizer, packer_opts_, is_clock, arch_); | ||
check_and_output_clustering(cluster_legalizer, vpr_setup_.PackerOpts, is_clock, &arch_); | ||
// Reset the cluster legalizer. This is required to load the packing. | ||
cluster_legalizer.reset(); | ||
// Regenerate the clustered netlist from the file generated previously. | ||
// FIXME: This writing and loading from a file is wasteful. Should generate | ||
// the clusters directly from the cluster legalizer. | ||
vpr_load_packing(vpr_setup_, *arch_); | ||
vpr_load_packing(vpr_setup_, arch_); | ||
load_cluster_constraints(); | ||
const ClusteredNetlist& clb_nlist = g_vpr_ctx.clustering().clb_nlist; | ||
|
||
// Verify the packing and print some info | ||
check_netlist(packer_opts_.pack_verbosity); | ||
check_netlist(vpr_setup_.PackerOpts.pack_verbosity); | ||
writeClusteredNetlistStats(vpr_setup_.FileNameOpts.write_block_usage); | ||
print_pb_type_count(clb_nlist); | ||
} | ||
|
||
void FullLegalizer::place_clusters(const ClusteredNetlist& clb_nlist, | ||
const PartialPlacement& p_placement) { | ||
void NaiveFullLegalizer::place_clusters(const ClusteredNetlist& clb_nlist, | ||
const PartialPlacement& p_placement) { | ||
// PLACING: | ||
// Create a lookup from the AtomBlockId to the APBlockId | ||
vtr::vector<AtomBlockId, APBlockId> atom_to_ap_block(atom_netlist_.blocks().size()); | ||
|
@@ -409,7 +446,7 @@ void FullLegalizer::place_clusters(const ClusteredNetlist& clb_nlist, | |
// - This may be needed to perform SA. Not needed right now. | ||
} | ||
|
||
void FullLegalizer::legalize(const PartialPlacement& p_placement) { | ||
void NaiveFullLegalizer::legalize(const PartialPlacement& p_placement) { | ||
// Create a scoped timer for the full legalizer | ||
vtr::ScopedStartFinishTimer full_legalizer_timer("AP Full Legalizer"); | ||
|
||
|
@@ -449,3 +486,65 @@ void FullLegalizer::legalize(const PartialPlacement& p_placement) { | |
post_place_sync(); | ||
} | ||
|
||
void APPack::legalize(const PartialPlacement& p_placement) { | ||
// Create a scoped timer for the full legalizer | ||
vtr::ScopedStartFinishTimer full_legalizer_timer("AP Full Legalizer"); | ||
|
||
// Convert the Partial Placement (APNetlist) to a flat placement (AtomNetlist). | ||
FlatPlacementInfo flat_placement_info(atom_netlist_); | ||
for (APBlockId ap_blk_id : ap_netlist_.blocks()) { | ||
PackMoleculeId mol_id = ap_netlist_.block_molecule(ap_blk_id); | ||
const t_pack_molecule& mol = prepacker_.get_molecule(mol_id); | ||
for (AtomBlockId atom_blk_id : mol.atom_block_ids) { | ||
if (!atom_blk_id.is_valid()) | ||
continue; | ||
flat_placement_info.blk_x_pos[atom_blk_id] = p_placement.block_x_locs[ap_blk_id]; | ||
flat_placement_info.blk_y_pos[atom_blk_id] = p_placement.block_y_locs[ap_blk_id]; | ||
flat_placement_info.blk_layer[atom_blk_id] = p_placement.block_layer_nums[ap_blk_id]; | ||
flat_placement_info.blk_sub_tile[atom_blk_id] = p_placement.block_sub_tiles[ap_blk_id]; | ||
} | ||
} | ||
|
||
// Run the Packer stage with the flat placement as a hint. | ||
try_pack(&vpr_setup_.PackerOpts, | ||
&vpr_setup_.AnalysisOpts, | ||
arch_, | ||
vpr_setup_.RoutingArch, | ||
vpr_setup_.user_models, | ||
vpr_setup_.library_models, | ||
vpr_setup_.PackerRRGraph, | ||
flat_placement_info); | ||
|
||
// The Packer stores the clusters into a .net file. Load the packing file. | ||
// FIXME: This should be removed. Reading from a file is strange. | ||
vpr_load_packing(vpr_setup_, arch_); | ||
load_cluster_constraints(); | ||
const ClusteredNetlist& clb_nlist = g_vpr_ctx.clustering().clb_nlist; | ||
|
||
// Verify the packing and print some info | ||
check_netlist(vpr_setup_.PackerOpts.pack_verbosity); | ||
writeClusteredNetlistStats(vpr_setup_.FileNameOpts.write_block_usage); | ||
print_pb_type_count(clb_nlist); | ||
|
||
// Pass the clustering into the Placer with the flat placement as a hint. | ||
// TODO: This should only be the initial placer. Running the full SA would | ||
// be more of a Detailed Placer. | ||
const auto& placement_net_list = (const Netlist<>&)clb_nlist; | ||
try_place(placement_net_list, | ||
vpr_setup_.PlacerOpts, | ||
vpr_setup_.RouterOpts, | ||
vpr_setup_.AnalysisOpts, | ||
vpr_setup_.NocOpts, | ||
arch_.Chans, | ||
&vpr_setup_.RoutingArch, | ||
vpr_setup_.Segments, | ||
arch_.directs, | ||
flat_placement_info, | ||
false /* is_flat */); | ||
|
||
// TODO: This was taken from vpr_api. Not sure why it is needed. Should be | ||
// made part of the placement and verify placement should check for | ||
// it. | ||
post_place_sync(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this makes sure the pin locations on blocks match the pin locations on the tile where they were placed (for equivalent_sites). I agree it probably makes more sense to put it at the end of placement. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I looked into how this is being used in the vpr_api and it is used after both try_place and reading a placement from a file. Its not super simple to remove, so I will leave this as a TODO. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, don't worry about it then -- we'd just move a call from one spot to two spots, which is arguably worse. |
||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason why is_flat is always false? If you're going to move this around as part of the initial placement / detailed placement separation you can ignore this comment, but eventually we should make sure we work with flat routing (which will just change the rr-graph for the placer delay lookup/matrix calculation I think).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its strange. The vpr_api.cpp file forces it to be false explicitly. Also in the try_place function it actually asserts that it is false:

I am not sure why it does this...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the placer delay model always wants the rr-graph without the intra-cluster routing. Strange we pass the flat in when it must be false, but reasonably harmless.