Skip to content

Commit ea8695a

Browse files
Merge pull request #2752 from AlexandreSinger/feature-ap-full-legalizer-upstreaming
[AP] Full Legalizer
2 parents 3e53a93 + e7fc394 commit ea8695a

33 files changed

+2292
-58
lines changed

vpr/src/analytical_place/analytical_placement_flow.cpp

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,21 @@
88
#include "analytical_placement_flow.h"
99
#include "ap_netlist.h"
1010
#include "atom_netlist.h"
11+
#include "full_legalizer.h"
1112
#include "gen_ap_netlist_from_atoms.h"
1213
#include "globals.h"
14+
#include "partial_placement.h"
1315
#include "prepack.h"
1416
#include "user_place_constraints.h"
1517
#include "vpr_context.h"
16-
#include "vpr_error.h"
1718
#include "vpr_types.h"
19+
#include "vtr_assert.h"
1820
#include "vtr_time.h"
1921

2022
void run_analytical_placement_flow(t_vpr_setup& vpr_setup) {
2123
(void)vpr_setup;
2224
// Start an overall timer for the Analytical Placement flow.
23-
vtr::ScopedStartFinishTimer timer("Analytical Placement Flow");
25+
vtr::ScopedStartFinishTimer timer("Analytical Placement");
2426

2527
// The global state used/modified by this flow.
2628
const AtomNetlist& atom_nlist = g_vpr_ctx.atom().nlist;
@@ -37,9 +39,38 @@ void run_analytical_placement_flow(t_vpr_setup& vpr_setup) {
3739
prepacker,
3840
constraints);
3941

40-
// AP is currently under-construction. Fail gracefully just in case this
41-
// is somehow being called.
42-
VPR_FATAL_ERROR(VPR_ERROR_AP,
43-
"Analytical Placement flow not implemented yet");
42+
// Run the Global Placer
43+
// For now, just put all the moveable blocks at the center of the device
44+
// grid. This will be replaced later. This is just for testing.
45+
PartialPlacement p_placement(ap_netlist);
46+
const size_t device_width = device_ctx.grid.width();
47+
const size_t device_height = device_ctx.grid.height();
48+
double device_center_x = static_cast<double>(device_width) / 2.0;
49+
double device_center_y = static_cast<double>(device_height) / 2.0;
50+
for (APBlockId ap_blk_id : ap_netlist.blocks()) {
51+
if (ap_netlist.block_mobility(ap_blk_id) != APBlockMobility::MOVEABLE)
52+
continue;
53+
// If the APBlock is moveable, put it on the center for the device.
54+
p_placement.block_x_locs[ap_blk_id] = device_center_x;
55+
p_placement.block_y_locs[ap_blk_id] = device_center_y;
56+
}
57+
VTR_ASSERT(p_placement.verify(ap_netlist,
58+
device_width,
59+
device_height,
60+
device_ctx.grid.get_num_layers()));
61+
62+
// Run the Full Legalizer.
63+
FullLegalizer full_legalizer(ap_netlist,
64+
vpr_setup,
65+
device_ctx.grid,
66+
device_ctx.arch,
67+
atom_nlist,
68+
prepacker,
69+
device_ctx.logical_block_types,
70+
vpr_setup.PackerRRGraph,
71+
device_ctx.arch->models,
72+
device_ctx.arch->model_library,
73+
vpr_setup.PackerOpts);
74+
full_legalizer.legalize(p_placement);
4475
}
4576

vpr/src/analytical_place/full_legalizer.cpp

Lines changed: 397 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/**
2+
* @file
3+
* @author Alex Singer
4+
* @date September 2024
5+
* @brief Defines the FullLegalizer class which takes a partial AP placement
6+
* and generates a fully legal clustering and placement which can be
7+
* routed by VTR.
8+
*/
9+
10+
#pragma once
11+
12+
#include <vector>
13+
14+
// Forward declarations
15+
class APNetlist;
16+
class AtomNetlist;
17+
class ClusteredNetlist;
18+
class DeviceGrid;
19+
class PartialPlacement;
20+
class Prepacker;
21+
struct t_arch;
22+
struct t_lb_type_rr_node;
23+
struct t_logical_block_type;
24+
struct t_model;
25+
struct t_packer_opts;
26+
struct t_vpr_setup;
27+
28+
/**
29+
* @brief The full legalizer in an AP flow
30+
*
31+
* Given a valid partial placement (of any level of legality), will produce a
32+
* fully legal clustering and placement for use in the rest of the VTR flow.
33+
*/
34+
class FullLegalizer {
35+
public:
36+
/**
37+
* @brief Constructor of the Full Legalizer class.
38+
*
39+
* Brings in all the necessary state here. This is the state needed from the
40+
* AP Context. the Packer Context, and the Placer Context.
41+
*/
42+
FullLegalizer(const APNetlist& ap_netlist,
43+
t_vpr_setup& vpr_setup,
44+
const DeviceGrid& device_grid,
45+
const t_arch* arch,
46+
const AtomNetlist& atom_netlist,
47+
const Prepacker& prepacker,
48+
const std::vector<t_logical_block_type>& logical_block_types,
49+
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs,
50+
const t_model* user_models,
51+
const t_model* library_models,
52+
const t_packer_opts& packer_opts)
53+
: ap_netlist_(ap_netlist),
54+
vpr_setup_(vpr_setup),
55+
device_grid_(device_grid),
56+
arch_(arch),
57+
atom_netlist_(atom_netlist),
58+
prepacker_(prepacker),
59+
logical_block_types_(logical_block_types),
60+
lb_type_rr_graphs_(lb_type_rr_graphs),
61+
user_models_(user_models),
62+
library_models_(library_models),
63+
packer_opts_(packer_opts) {}
64+
65+
/**
66+
* @brief Perform legalization on the given partial placement solution
67+
*
68+
* @param p_placement A valid partial placement (passes verify method).
69+
* This implies that all blocks are placed on the
70+
* device grid and fixed blocks are observed.
71+
*/
72+
void legalize(const PartialPlacement& p_placement);
73+
74+
private:
75+
/**
76+
* @brief Helper method to create the clusters from the given partial
77+
* placement.
78+
* TODO: Should return a ClusteredNetlist object, but need to wait until
79+
* it is separated from load_cluster_constraints.
80+
*/
81+
void create_clusters(const PartialPlacement& p_placement);
82+
83+
/**
84+
* @brief Helper method to place the clusters based on the given partial
85+
* placement.
86+
*/
87+
void place_clusters(const ClusteredNetlist& clb_nlist,
88+
const PartialPlacement& p_placement);
89+
90+
// AP Context Info
91+
const APNetlist& ap_netlist_;
92+
// Overall Setup Info
93+
// FIXME: I do not like bringing all of this in. Perhaps clean up the methods
94+
// that use it.
95+
t_vpr_setup& vpr_setup_;
96+
// Device Context Info
97+
const DeviceGrid& device_grid_;
98+
const t_arch* arch_;
99+
// Packing Context Info
100+
const AtomNetlist& atom_netlist_;
101+
const Prepacker& prepacker_;
102+
const std::vector<t_logical_block_type>& logical_block_types_;
103+
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs_;
104+
const t_model* user_models_;
105+
const t_model* library_models_;
106+
const t_packer_opts& packer_opts_;
107+
// Placement Context Info
108+
// TODO: Populate this once the placer is cleaned up some.
109+
};
110+

vpr/src/analytical_place/partial_placement.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
bool PartialPlacement::verify_locs(const APNetlist& netlist,
1414
size_t grid_width,
15-
size_t grid_height) {
15+
size_t grid_height) const {
1616
// Make sure all of the loc values are there.
1717
if (block_x_locs.size() != netlist.blocks().size())
1818
return false;
@@ -43,7 +43,7 @@ bool PartialPlacement::verify_locs(const APNetlist& netlist,
4343
}
4444

4545
bool PartialPlacement::verify_layer_nums(const APNetlist& netlist,
46-
size_t grid_num_layers) {
46+
size_t grid_num_layers) const {
4747
// Make sure all of the layer nums are there
4848
if (block_layer_nums.size() != netlist.blocks().size())
4949
return false;
@@ -62,7 +62,7 @@ bool PartialPlacement::verify_layer_nums(const APNetlist& netlist,
6262
return true;
6363
}
6464

65-
bool PartialPlacement::verify_sub_tiles(const APNetlist& netlist) {
65+
bool PartialPlacement::verify_sub_tiles(const APNetlist& netlist) const {
6666
// Make sure all of the sub tiles are there
6767
if (block_sub_tiles.size() != netlist.blocks().size())
6868
return false;
@@ -88,7 +88,7 @@ bool PartialPlacement::verify_sub_tiles(const APNetlist& netlist) {
8888
bool PartialPlacement::verify(const APNetlist& netlist,
8989
size_t grid_width,
9090
size_t grid_height,
91-
size_t grid_num_layers) {
91+
size_t grid_num_layers) const {
9292
// Check that all the other verify methods passed.
9393
if (!verify_locs(netlist, grid_width, grid_height))
9494
return false;

vpr/src/analytical_place/partial_placement.h

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212

1313
#pragma once
1414

15+
#include <cmath>
1516
#include "ap_netlist.h"
17+
#include "physical_types.h"
1618
#include "vtr_vector.h"
1719

1820
/**
@@ -94,6 +96,44 @@ struct PartialPlacement {
9496
}
9597
}
9698

99+
/**
100+
* @brief Get the location of the physical tile that contains the given
101+
* AP block.
102+
*
103+
* VTR uses an integer grid. In AP, we consider a tile at (1,1) to be
104+
* centered at (1.5,1.5). When converting from doubles back to integer
105+
* tiles, we simply take the floor, so the tile above would receive all
106+
* points from [(1,1) to (2,2)). When converting fixed blocks from the
107+
* integral VPR grid to the AP locations, we should therefore add (0.5,0.5)
108+
* to them so they are centered in their grid tiles (assuming the tiles are
109+
* 1x1).
110+
*
111+
* FIXME: Ideally this should return an ID to the tile, not a location.
112+
* This is important since there is a distinction between the two.
113+
* We know a block will be at that tile, but it would not be at the
114+
* corner of the block (likely it would be at the center).
115+
*/
116+
inline t_physical_tile_loc get_containing_tile_loc(APBlockId blk_id) const {
117+
// We take the floor here since we want to know which tile contains this
118+
// block. On a grid, if the block is located at x=0.99999, it would still
119+
// be in the first tile. This is because we assume that the blocks will
120+
// ultimately end up in the center of the tile, not at the top left
121+
// corner of it. The physical tile loc is just a way of identifying that
122+
// tile.
123+
// TODO: This may be a bit more complicated than this. This assumes that
124+
// all tiles are 1x1, but it could be the case that this is on
125+
// the edge of a much larger block. In reality this should try
126+
// to go into the tile where it is closest to the center. What
127+
// is written here is not necessarily wrong, but it may put blocks
128+
// which on are the edge of large blocks into the large blocks.
129+
// However, this may not even matter if the partial legalizer is
130+
// doing its job!
131+
int tile_x_loc = std::floor(block_x_locs[blk_id]);
132+
int tile_y_loc = std::floor(block_y_locs[blk_id]);
133+
int tile_layer = std::floor(block_layer_nums[blk_id]);
134+
return t_physical_tile_loc(tile_x_loc, tile_y_loc, tile_layer);
135+
}
136+
97137
/**
98138
* @brief Verify the block_x_locs and block_y_locs vectors
99139
*
@@ -108,7 +148,7 @@ struct PartialPlacement {
108148
*/
109149
bool verify_locs(const APNetlist& netlist,
110150
size_t grid_width,
111-
size_t grid_height);
151+
size_t grid_height) const;
112152

113153
/**
114154
* @brief Verify the block_layer_nums vector
@@ -121,7 +161,8 @@ struct PartialPlacement {
121161
* @param netlist The APNetlist used to generate this placement
122162
* @param grid_num_layers The number of layers in the device grid
123163
*/
124-
bool verify_layer_nums(const APNetlist& netlist, size_t grid_num_layers);
164+
bool verify_layer_nums(const APNetlist& netlist,
165+
size_t grid_num_layers) const;
125166

126167
/**
127168
* @brief Verify the sub_tiles
@@ -131,7 +172,7 @@ struct PartialPlacement {
131172
*
132173
* @param netlist The APNetlist used to generate this placement
133174
*/
134-
bool verify_sub_tiles(const APNetlist& netlist);
175+
bool verify_sub_tiles(const APNetlist& netlist) const;
135176

136177
/**
137178
* @brief Verify the entire partial placement object
@@ -146,6 +187,6 @@ struct PartialPlacement {
146187
bool verify(const APNetlist& netlist,
147188
size_t grid_width,
148189
size_t grid_height,
149-
size_t grid_num_layers);
190+
size_t grid_num_layers) const;
150191
};
151192

vpr/src/base/vpr_api.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,15 @@ bool vpr_flow(t_vpr_setup& vpr_setup, t_arch& arch) {
411411
// TODO: Make this return a bool if the placement was successful or not.
412412
run_analytical_placement_flow(vpr_setup);
413413
}
414+
// Print the placement generated by AP to a .place file.
415+
auto& filename_opts = vpr_setup.FileNameOpts;
416+
auto& cluster_ctx = g_vpr_ctx.clustering();
417+
const auto& block_locs = g_vpr_ctx.placement().block_locs();
418+
auto& placement_id = g_vpr_ctx.mutable_placement().placement_id;
419+
placement_id = print_place(filename_opts.NetFile.c_str(),
420+
cluster_ctx.clb_nlist.netlist_id().c_str(),
421+
filename_opts.PlaceFile.c_str(),
422+
block_locs);
414423
}
415424

416425
bool is_flat = vpr_setup.RouterOpts.flat_routing;

vpr/src/pack/cluster_legalizer.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,27 @@
3838
#include "vtr_vector.h"
3939
#include "vtr_vector_map.h"
4040

41+
/**
42+
* @brief Counts the total number of logic models that the architecture can
43+
* implement.
44+
*
45+
* @param user_models A linked list of logic models.
46+
* @return The total number of models in the linked list
47+
*/
48+
static size_t count_models(const t_model* user_models) {
49+
if (user_models == nullptr)
50+
return 0;
51+
52+
size_t n_models = 0;
53+
const t_model* cur_model = user_models;
54+
while (cur_model != nullptr) {
55+
n_models++;
56+
cur_model = cur_model->next;
57+
}
58+
59+
return n_models;
60+
}
61+
4162
/*
4263
* @brief Gets the max cluster size that any logical block can have.
4364
*
@@ -1636,7 +1657,8 @@ ClusterLegalizer::ClusterLegalizer(const AtomNetlist& atom_netlist,
16361657
const Prepacker& prepacker,
16371658
const std::vector<t_logical_block_type>& logical_block_types,
16381659
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs,
1639-
size_t num_models,
1660+
const t_model* user_models,
1661+
const t_model* library_models,
16401662
const std::vector<std::string>& target_external_pin_util_str,
16411663
const t_pack_high_fanout_thresholds& high_fanout_thresholds,
16421664
ClusterLegalizationStrategy cluster_legalization_strategy,
@@ -1661,7 +1683,7 @@ ClusterLegalizer::ClusterLegalizer(const AtomNetlist& atom_netlist,
16611683
// Get a reference to the rr graphs.
16621684
lb_type_rr_graphs_ = lb_type_rr_graphs;
16631685
// Get the number of models in the architecture.
1664-
num_models_ = num_models;
1686+
num_models_ = count_models(user_models) + count_models(library_models);
16651687
// Find all NoC router atoms.
16661688
std::vector<AtomBlockId> noc_atoms = find_noc_router_atoms(atom_netlist);
16671689
update_noc_reachability_partitions(noc_atoms,

vpr/src/pack/cluster_legalizer.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,10 @@ class ClusterLegalizer {
215215
* different cluster types. A reference is stored
216216
* in the class to be used to allocate and load
217217
* the router data.
218-
* @param num_models The total number of models in the architecture.
219-
* This is the sum of the number of the user and
220-
* library models. Used internally to allocate data
221-
* structures.
218+
* @param user_models A linked list of the user models. Used to allocate
219+
* an internal structure.
220+
* @param library_models A linked list of the library models. Used to
221+
* allocate an internal structure.
222222
* @param target_external_pin_util_str A string used to initialize the
223223
* target external pin utilization of
224224
* each cluster type.
@@ -246,7 +246,8 @@ class ClusterLegalizer {
246246
const Prepacker& prepacker,
247247
const std::vector<t_logical_block_type>& logical_block_types,
248248
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs,
249-
size_t num_models,
249+
const t_model* user_models,
250+
const t_model* library_models,
250251
const std::vector<std::string>& target_external_pin_util_str,
251252
const t_pack_high_fanout_thresholds& high_fanout_thresholds,
252253
ClusterLegalizationStrategy cluster_legalization_strategy,

0 commit comments

Comments
 (0)