Skip to content

Commit 40797ae

Browse files
authored
Merge pull request #2742 from AlexandreSinger/feature-ap-partial-placement-upstreaming
[AP] Added Partial Placement Object
2 parents 372f0dc + 2b6a935 commit 40797ae

File tree

3 files changed

+387
-0
lines changed

3 files changed

+387
-0
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/**
2+
* @file
3+
* @author Alex Singer
4+
* @date September 2024
5+
* @brief The definitions of the PartialPlacement methods
6+
*/
7+
8+
#include "partial_placement.h"
9+
#include <cmath>
10+
#include <cstddef>
11+
#include "ap_netlist.h"
12+
13+
bool PartialPlacement::verify_locs(const APNetlist& netlist,
14+
size_t grid_width,
15+
size_t grid_height) {
16+
// Make sure all of the loc values are there.
17+
if (block_x_locs.size() != netlist.blocks().size())
18+
return false;
19+
if (block_y_locs.size() != netlist.blocks().size())
20+
return false;
21+
// Make sure all locs are on the device and fixed locs are correct
22+
for (APBlockId blk_id : netlist.blocks()) {
23+
double x_pos = block_x_locs[blk_id];
24+
double y_pos = block_y_locs[blk_id];
25+
if (std::isnan(x_pos) ||
26+
x_pos < 0.0 ||
27+
x_pos >= grid_width)
28+
return false;
29+
if (std::isnan(y_pos) ||
30+
y_pos < 0.0 ||
31+
y_pos >= grid_height)
32+
return false;
33+
if (netlist.block_mobility(blk_id) == APBlockMobility::FIXED) {
34+
const APFixedBlockLoc& fixed_loc = netlist.block_loc(blk_id);
35+
if (fixed_loc.x != -1 && x_pos != fixed_loc.x)
36+
return false;
37+
if (fixed_loc.y != -1 && y_pos != fixed_loc.y)
38+
return false;
39+
}
40+
}
41+
// If all previous checks passed, return true
42+
return true;
43+
}
44+
45+
bool PartialPlacement::verify_layer_nums(const APNetlist& netlist,
46+
size_t grid_num_layers) {
47+
// Make sure all of the layer nums are there
48+
if (block_layer_nums.size() != netlist.blocks().size())
49+
return false;
50+
// Make sure all layer_nums are on the device and fixed locs are correct.
51+
for (APBlockId blk_id : netlist.blocks()) {
52+
double layer_num = block_layer_nums[blk_id];
53+
if (layer_num < 0.0 || layer_num >= static_cast<double>(grid_num_layers))
54+
return false;
55+
if (netlist.block_mobility(blk_id) == APBlockMobility::FIXED) {
56+
const APFixedBlockLoc& fixed_loc = netlist.block_loc(blk_id);
57+
if (fixed_loc.layer_num != -1 && layer_num != fixed_loc.layer_num)
58+
return false;
59+
}
60+
}
61+
// If all previous checks passed, return true
62+
return true;
63+
}
64+
65+
bool PartialPlacement::verify_sub_tiles(const APNetlist& netlist) {
66+
// Make sure all of the sub tiles are there
67+
if (block_sub_tiles.size() != netlist.blocks().size())
68+
return false;
69+
// For now, we do not really do much with the sub_tile information. Ideally
70+
// we should check that all blocks have a sub_tile that actually exists
71+
// (a tile actually has a sub_tile of that idx); however, this may be
72+
// challenging to enforce. For now, just ensure that the number is
73+
// non-negative (implying a choice was made).
74+
for (APBlockId blk_id : netlist.blocks()) {
75+
int sub_tile = block_sub_tiles[blk_id];
76+
if (sub_tile < 0)
77+
return false;
78+
if (netlist.block_mobility(blk_id) == APBlockMobility::FIXED) {
79+
const APFixedBlockLoc& fixed_loc = netlist.block_loc(blk_id);
80+
if (fixed_loc.sub_tile != -1 && sub_tile != fixed_loc.sub_tile)
81+
return false;
82+
}
83+
}
84+
// If all previous checks passed, return true
85+
return true;
86+
}
87+
88+
bool PartialPlacement::verify(const APNetlist& netlist,
89+
size_t grid_width,
90+
size_t grid_height,
91+
size_t grid_num_layers) {
92+
// Check that all the other verify methods passed.
93+
if (!verify_locs(netlist, grid_width, grid_height))
94+
return false;
95+
if (!verify_layer_nums(netlist, grid_num_layers))
96+
return false;
97+
if (!verify_sub_tiles(netlist))
98+
return false;
99+
// If all other verify methods passed, then the placement is valid.
100+
return true;
101+
}
102+
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/**
2+
* @file
3+
* @author Alex Singer
4+
* @date September 2024
5+
* @brief The declaration of the PartialPlacement object
6+
*
7+
* The partial placement object stores the placement of the APNetlist blocks
8+
* during different stages of the Analytical Placement flow. The Partial
9+
* Placement need not represent a legal placement; however, the placed blocks
10+
* will always be on the device and will respect fixed block locations.
11+
*/
12+
13+
#pragma once
14+
15+
#include "ap_netlist.h"
16+
#include "vtr_vector.h"
17+
18+
/**
19+
* @brief A partial placement during the Analytical Placement flow
20+
*
21+
* The goal of this class is to contain positional information about the blocks
22+
* that gets passed around during analytical placement.
23+
*
24+
* The placement of a given APBlock is given by the following values:
25+
* - x_loc The x-position of the APBlock on the device grid
26+
* - y_loc The y-position of the APBlock on the device grid
27+
* - layer_num The layer on the device grid this block is on
28+
* - sub_tile The sub-tile this APBlock wants to be a part of
29+
* TODO: Not sure if we want to keep the sub tile, but it may be useful for
30+
* transferring information from the PartialLegalizer to the FullLegalizer.
31+
*
32+
* x_loc, y_loc, and layer_num are represented by doubles since APBlocks can be
33+
* placed in continuous space, rather than constrained to the integer device
34+
* grid of legal locations. These are doubles rather than floats since they
35+
* better fit the matrix solver we currently use.
36+
*
37+
* layer_num is represented by an int since it is not decided by an analytical
38+
* solver, but rather by the legalizers; so it does not need to be in continuous
39+
* space.
40+
*
41+
* This object assumes that the APNetlist object is static during the operation
42+
* of Analytical Placement (no blocks are added or removed).
43+
*
44+
* Note: The placement information was stored in this object as a struct of
45+
* arrays instead of an array of structs since it is assumed that the
46+
* main operations being performed on this placement will be analytical;
47+
* thus the x positions and y positions will likely be stored and computed
48+
* as separate continuous vectors.
49+
*/
50+
struct PartialPlacement {
51+
/// @brief The x locations of all the APBlocks
52+
vtr::vector<APBlockId, double> block_x_locs;
53+
/// @brief The y locations of all the APBlocks
54+
vtr::vector<APBlockId, double> block_y_locs;
55+
/// @brief The layers of the device of all the APBlocks
56+
vtr::vector<APBlockId, double> block_layer_nums;
57+
/// @brief The sub tiles of all the APBlocks
58+
vtr::vector<APBlockId, int> block_sub_tiles;
59+
60+
// Remove the default constructor. Need to construct this using an APNetlist.
61+
PartialPlacement() = delete;
62+
63+
/**
64+
* @brief Construct the partial placement
65+
*
66+
* Uses the APNetlist object to allocate space for the locations of all
67+
* APBlocks.
68+
*
69+
* @param netlist The APNetlist which contains the blocks to be placed.
70+
*/
71+
PartialPlacement(const APNetlist& netlist)
72+
: block_x_locs(netlist.blocks().size(), -1.0),
73+
block_y_locs(netlist.blocks().size(), -1.0),
74+
block_layer_nums(netlist.blocks().size(), 0.0),
75+
block_sub_tiles(netlist.blocks().size(), 0) {
76+
// Note: All blocks are initialized to:
77+
// x_loc = -1.0
78+
// y_loc = -1.0
79+
// layer_num = 0.0
80+
// sub_tile = 0
81+
// Load the fixed block locations
82+
for (APBlockId blk_id : netlist.blocks()) {
83+
if (netlist.block_mobility(blk_id) != APBlockMobility::FIXED)
84+
continue;
85+
const APFixedBlockLoc &loc = netlist.block_loc(blk_id);
86+
if (loc.x != -1)
87+
block_x_locs[blk_id] = loc.x;
88+
if (loc.y != -1)
89+
block_y_locs[blk_id] = loc.y;
90+
if (loc.layer_num != -1)
91+
block_layer_nums[blk_id] = loc.layer_num;
92+
if (loc.sub_tile != -1)
93+
block_sub_tiles[blk_id] = loc.sub_tile;
94+
}
95+
}
96+
97+
/**
98+
* @brief Verify the block_x_locs and block_y_locs vectors
99+
*
100+
* Currently ensures:
101+
* - All blocks have locs
102+
* - All blocks are on the device
103+
* - All fixed locs are correct
104+
*
105+
* @param netlist The APNetlist used to generate this placement
106+
* @param grid_width The width of the device grid
107+
* @param grid_height The height of the device grid
108+
*/
109+
bool verify_locs(const APNetlist& netlist,
110+
size_t grid_width,
111+
size_t grid_height);
112+
113+
/**
114+
* @brief Verify the block_layer_nums vector
115+
*
116+
* Currently ensures:
117+
* - All blocks have layer_nums
118+
* - All blocks are on the device
119+
* - All fixed layers are correct
120+
*
121+
* @param netlist The APNetlist used to generate this placement
122+
* @param grid_num_layers The number of layers in the device grid
123+
*/
124+
bool verify_layer_nums(const APNetlist& netlist, size_t grid_num_layers);
125+
126+
/**
127+
* @brief Verify the sub_tiles
128+
*
129+
* Currently ensures:
130+
* - All sub_tiles are non-negative (implies unset)
131+
*
132+
* @param netlist The APNetlist used to generate this placement
133+
*/
134+
bool verify_sub_tiles(const APNetlist& netlist);
135+
136+
/**
137+
* @brief Verify the entire partial placement object
138+
*
139+
* Runs all of the verification checks above.
140+
*
141+
* @param netlist The APNetlist used to generate this placement
142+
* @param grid_width The width of the device grid
143+
* @param grid_height The height of the device grid
144+
* @param grid_num_layers The number of layers in the device grid
145+
*/
146+
bool verify(const APNetlist& netlist,
147+
size_t grid_width,
148+
size_t grid_height,
149+
size_t grid_num_layers);
150+
};
151+
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/**
2+
* @file
3+
* @author Alex Singer
4+
* @date September 2024
5+
* @brief Unit tests for the PartialPlacement object
6+
*
7+
* Very quick functionality checks to make sure that the methods inside of the
8+
* PartialPlacement object are working as expected.
9+
*/
10+
11+
#include "catch2/catch_test_macros.hpp"
12+
13+
#include "ap_netlist.h"
14+
#include "partial_placement.h"
15+
#include "vpr_types.h"
16+
17+
namespace {
18+
19+
TEST_CASE("test_ap_partial_placement_verify", "[vpr_ap]") {
20+
// Create a test netlist object.
21+
APNetlist test_netlist("test_netlist");
22+
// Create a few molecules.
23+
t_pack_molecule mol_a;
24+
t_pack_molecule mol_b;
25+
t_pack_molecule mol_c;
26+
// Create blocks for these molecules.
27+
APBlockId block_id_a = test_netlist.create_block("BlockA", &mol_a);
28+
APBlockId block_id_b = test_netlist.create_block("BlockB", &mol_b);
29+
APBlockId block_id_c = test_netlist.create_block("BlockC", &mol_c);
30+
// Fix BlockC.
31+
APFixedBlockLoc fixed_block_loc;
32+
fixed_block_loc.x = 12;
33+
fixed_block_loc.y = 42;
34+
fixed_block_loc.layer_num = 2;
35+
fixed_block_loc.sub_tile = 1;
36+
test_netlist.set_block_loc(block_id_c, fixed_block_loc);
37+
38+
// Create the PartialPlacement object.
39+
PartialPlacement test_placement(test_netlist);
40+
41+
SECTION("Test constructor places fixed blocks correctly") {
42+
REQUIRE(test_placement.block_x_locs[block_id_c] == fixed_block_loc.x);
43+
REQUIRE(test_placement.block_y_locs[block_id_c] == fixed_block_loc.y);
44+
REQUIRE(test_placement.block_layer_nums[block_id_c] == fixed_block_loc.layer_num);
45+
REQUIRE(test_placement.block_sub_tiles[block_id_c] == fixed_block_loc.sub_tile);
46+
}
47+
48+
// Place the blocks
49+
// Place BlockA
50+
test_placement.block_x_locs[block_id_a] = 0;
51+
test_placement.block_y_locs[block_id_a] = 0;
52+
test_placement.block_layer_nums[block_id_a] = 0;
53+
test_placement.block_sub_tiles[block_id_a] = 0;
54+
// Place BlockB
55+
test_placement.block_x_locs[block_id_b] = 0;
56+
test_placement.block_y_locs[block_id_b] = 0;
57+
test_placement.block_layer_nums[block_id_b] = 0;
58+
test_placement.block_sub_tiles[block_id_b] = 0;
59+
60+
SECTION("Test verify returns true when the placement is valid") {
61+
// NOTE: Using a very large device.
62+
REQUIRE(test_placement.verify(test_netlist, 100, 100, 100));
63+
// Picking sizes that just fit.
64+
REQUIRE(test_placement.verify(test_netlist, 13, 100, 100));
65+
REQUIRE(test_placement.verify(test_netlist, 100, 43, 100));
66+
REQUIRE(test_placement.verify(test_netlist, 100, 100, 3));
67+
REQUIRE(test_placement.verify(test_netlist, 13, 43, 3));
68+
}
69+
70+
SECTION("Test verify methods all return true when verify returns true") {
71+
REQUIRE(test_placement.verify_locs(test_netlist, 100, 100));
72+
REQUIRE(test_placement.verify_layer_nums(test_netlist, 100));
73+
REQUIRE(test_placement.verify_sub_tiles(test_netlist));
74+
}
75+
76+
SECTION("Test verify returns false when blocks are outside grid") {
77+
// NOTE: Picking device sizes that are just small enough that BlockC
78+
// is off the device.
79+
REQUIRE(!test_placement.verify_locs(test_netlist, 100, 1));
80+
REQUIRE(!test_placement.verify_locs(test_netlist, 1, 100));
81+
REQUIRE(!test_placement.verify_layer_nums(test_netlist, 1));
82+
// Make sure that the verify method also catches these cases
83+
REQUIRE(!test_placement.verify(test_netlist, 100, 1, 100));
84+
REQUIRE(!test_placement.verify(test_netlist, 1, 100, 100));
85+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 1));
86+
// Move BlockA off the grid into the negative direction
87+
test_placement.block_x_locs[block_id_a] = -1;
88+
REQUIRE(!test_placement.verify_locs(test_netlist, 100, 100));
89+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
90+
test_placement.block_x_locs[block_id_a] = 0;
91+
test_placement.block_y_locs[block_id_a] = -1;
92+
REQUIRE(!test_placement.verify_locs(test_netlist, 100, 100));
93+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
94+
test_placement.block_y_locs[block_id_a] = 0;
95+
test_placement.block_layer_nums[block_id_a] = -1;
96+
REQUIRE(!test_placement.verify_layer_nums(test_netlist, 100));
97+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
98+
test_placement.block_layer_nums[block_id_a] = 0;
99+
test_placement.block_sub_tiles[block_id_a] = -1;
100+
REQUIRE(!test_placement.verify_sub_tiles(test_netlist));
101+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
102+
test_placement.block_sub_tiles[block_id_a] = 0;
103+
// Make sure everything is valid again
104+
REQUIRE(test_placement.verify(test_netlist, 100, 100, 100));
105+
}
106+
107+
SECTION("Test verify returns false when fixed blocks are moved") {
108+
// Move BlockC's x-coordinate
109+
test_placement.block_x_locs[block_id_c] = 0;
110+
REQUIRE(!test_placement.verify_locs(test_netlist, 100, 100));
111+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
112+
test_placement.block_x_locs[block_id_c] = fixed_block_loc.x;
113+
// Move BlockC's y-coordinate
114+
test_placement.block_y_locs[block_id_c] = 0;
115+
REQUIRE(!test_placement.verify_locs(test_netlist, 100, 100));
116+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
117+
test_placement.block_y_locs[block_id_c] = fixed_block_loc.y;
118+
// Move BlockC's layer num
119+
test_placement.block_layer_nums[block_id_c] = 0;
120+
REQUIRE(!test_placement.verify_layer_nums(test_netlist, 100));
121+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
122+
test_placement.block_layer_nums[block_id_c] = fixed_block_loc.layer_num;
123+
// Move BlockC's sub tile
124+
test_placement.block_sub_tiles[block_id_c] = 0;
125+
REQUIRE(!test_placement.verify_sub_tiles(test_netlist));
126+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
127+
test_placement.block_sub_tiles[block_id_c] = fixed_block_loc.sub_tile;
128+
// Make sure everything was put back correctly.
129+
REQUIRE(test_placement.verify(test_netlist, 100, 100, 100));
130+
}
131+
}
132+
133+
} // namespace
134+

0 commit comments

Comments
 (0)