13
13
14
14
#pragma once
15
15
16
+ #include < functional>
16
17
#include < memory>
17
18
#include < vector>
18
19
#include " ap_netlist_fwd.h"
19
20
#include " flat_placement_bins.h"
20
21
#include " flat_placement_density_manager.h"
22
+ #include " model_grouper.h"
21
23
#include " primitive_vector.h"
24
+ #include " vtr_geometry.h"
25
+ #include " vtr_prefix_sum.h"
22
26
#include " vtr_vector.h"
23
27
24
28
// Forward declarations
@@ -90,6 +94,7 @@ class PartialLegalizer {
90
94
std::unique_ptr<PartialLegalizer> make_partial_legalizer (e_partial_legalizer legalizer_type,
91
95
const APNetlist& netlist,
92
96
std::shared_ptr<FlatPlacementDensityManager> density_manager,
97
+ const Prepacker& prepacker,
93
98
int log_verbosity);
94
99
95
100
/* *
@@ -240,6 +245,97 @@ class FlowBasedLegalizer : public PartialLegalizer {
240
245
void legalize (PartialPlacement& p_placement) final ;
241
246
};
242
247
248
+ /* *
249
+ * @brief A cluster of flat placement bins.
250
+ */
251
+ typedef typename std::vector<FlatPlacementBinId> FlatPlacementBinCluster;
252
+
253
+ /* *
254
+ * @brief Enum for the direction of a partition.
255
+ */
256
+ enum class e_partition_dir {
257
+ VERTICAL,
258
+ HORIZONTAL
259
+ };
260
+
261
+ /* *
262
+ * @brief Spatial window used to spread the blocks contained within.
263
+ *
264
+ * This window's region is identified and grown until it has enough space to
265
+ * accomodate the blocks stored within. This window is then successivly
266
+ * partitioned until it is small enough (blocks are not too dense).
267
+ */
268
+ struct SpreadingWindow {
269
+ // / @brief The blocks contained within this window.
270
+ std::vector<APBlockId> contained_blocks;
271
+
272
+ // / @brief The 2D region of space that this window covers.
273
+ vtr::Rect <double > region;
274
+ };
275
+
276
+ /* *
277
+ * @brief Struct to hold the information from partitioning a window. Contains
278
+ * the two window partitions and some information about how they were
279
+ * generated.
280
+ */
281
+ struct PartitionedWindow {
282
+ // / @brief The direction of the partition.
283
+ e_partition_dir partition_dir;
284
+
285
+ // / @brief The position that the parent window was split at.
286
+ double pivot_pos;
287
+
288
+ // / @brief The lower window. This is the left partition when the direction
289
+ // / is vertical, and the bottom partition when the direction is
290
+ // / horizontal.
291
+ SpreadingWindow lower_window;
292
+
293
+ // / @brief The upper window. This is the right partition when the direction
294
+ // / is vertical, and the top partition when the direction is
295
+ // / horizontal.
296
+ SpreadingWindow upper_window;
297
+ };
298
+
299
+ /* *
300
+ * @brief Wrapper class around the prefix sum class which creates a prefix sum
301
+ * for each model type and has helper methods for getting the sums over
302
+ * regions.
303
+ */
304
+ class PerModelPrefixSum2D {
305
+ public:
306
+ PerModelPrefixSum2D () = default ;
307
+
308
+ /* *
309
+ * @brief Construct prefix sums for each of the models in the architecture.
310
+ *
311
+ * Uses the density manager to get the size of the placeable region.
312
+ *
313
+ * The lookup is a lambda used to populate the prefix sum. It provides
314
+ * the model index, x, and y to be populated.
315
+ */
316
+ PerModelPrefixSum2D (const FlatPlacementDensityManager& density_manager,
317
+ t_model* user_models,
318
+ t_model* library_models,
319
+ std::function<float (int , size_t , size_t )> lookup);
320
+
321
+ /* *
322
+ * @brief Get the sum for a given model over the given region.
323
+ */
324
+ float get_model_sum (int model_index,
325
+ const vtr::Rect <double >& region) const ;
326
+
327
+ /* *
328
+ * @brief Get the multi-dimensional sum over the given model indices over
329
+ * the given region.
330
+ */
331
+ PrimitiveVector get_sum (const std::vector<int >& model_indices,
332
+ const vtr::Rect <double >& region) const ;
333
+
334
+ private:
335
+ // / @brief Per-Model Prefix Sums
336
+ std::vector<vtr::PrefixSum2D<float >> model_prefix_sum_;
337
+ };
338
+
243
339
/* *
244
340
* @brief A bi-paritioning spreading full legalizer.
245
341
*
@@ -258,6 +354,19 @@ class FlowBasedLegalizer : public PartialLegalizer {
258
354
* GPlace3.0: https://doi.org/10.1145/3233244
259
355
*/
260
356
class BiPartitioningPartialLegalizer : public PartialLegalizer {
357
+ private:
358
+ // / @brief The maximum gap between overfilled bins we can have in a flat
359
+ // / placement bin cluster. For example, if this is set to 1, we will
360
+ // / allow two overfilled bins to be clustered together if they only
361
+ // / have 1 non-overfilled bin of gap between them.
362
+ // / The rational behind this is that it allows us to predict that the windows
363
+ // / created for each cluster will overlap if they are within some gap distance.
364
+ // / Increasing this number too much may cluster bins together too much and
365
+ // / create large windows; decreasing this number will put more pressure on
366
+ // / the window generation code, which can increase window size and runtime.
367
+ // / TODO: Should this be distance instead of number of bins?
368
+ static constexpr int max_bin_cluster_gap_ = 1 ;
369
+
261
370
public:
262
371
/* *
263
372
* @brief Constructor for the bi-partitioning partial legalizer.
@@ -267,6 +376,7 @@ class BiPartitioningPartialLegalizer : public PartialLegalizer {
267
376
*/
268
377
BiPartitioningPartialLegalizer (const APNetlist& netlist,
269
378
std::shared_ptr<FlatPlacementDensityManager> density_manager,
379
+ const Prepacker& prepacker,
270
380
int log_verbosity);
271
381
272
382
/* *
@@ -278,8 +388,130 @@ class BiPartitioningPartialLegalizer : public PartialLegalizer {
278
388
*/
279
389
void legalize (PartialPlacement& p_placement) final ;
280
390
391
+ private:
392
+ // ========================================================================
393
+ // Identifying spreading windows
394
+ // ========================================================================
395
+
396
+ /* *
397
+ * @brief Identify spreading windows which contain overfilled bins in the
398
+ * given model group on the device and do not overlap.
399
+ *
400
+ * This process is split into 4 stages:
401
+ * 1) Overfilled bins are identified and clustered.
402
+ * 2) Grow windows around the overfilled bin clusters. These windows
403
+ * will grow until there is just enough space to accomodate the blocks
404
+ * within the window (capacity of the window is larger than the utilization).
405
+ * 3) Merge overlapping windows.
406
+ * 4) Move the blocks within these window regions from their bins into
407
+ * their windows. This updates the current utilization of bins, making
408
+ * spreading easier.
409
+ *
410
+ * We identify non-overlapping windows for different model groups independtly
411
+ * for a few reasons:
412
+ * - Each model group, by design, can be spread independent of each other.
413
+ * This reduces the problem size by the number of groups.
414
+ * - Without model groups, one block placed on the wrong side of the chip
415
+ * may create a window the size of the entire chip! This would rip up and
416
+ * spread all the blocks in the chip, which is very expensive.
417
+ * - This allows us to ignore block models which are already in legal
418
+ * positions.
419
+ */
420
+ std::vector<SpreadingWindow> identify_non_overlapping_windows (ModelGroupId group_id);
421
+
422
+ /* *
423
+ * @brief Identifies clusters of overfilled bins for the given model group.
424
+ *
425
+ * This locates clusters of overfilled bins which are within a given
426
+ * distance from each other.
427
+ */
428
+ std::vector<FlatPlacementBinCluster> get_overfilled_bin_clusters (ModelGroupId group_id);
429
+
430
+ /* *
431
+ * @brief Creates and grows minimum spanning windows around the given
432
+ * overfilled bin clusters.
433
+ *
434
+ * Here, minimum means that the windows are just large enough such that the
435
+ * capacity of the bins within the window is larger than the utilization for
436
+ * the given model group.
437
+ */
438
+ std::vector<SpreadingWindow> get_min_windows_around_clusters (
439
+ const std::vector<FlatPlacementBinCluster>& overfilled_bin_clusters,
440
+ ModelGroupId group_id);
441
+
442
+ /* *
443
+ * @brief Merges overlapping windows in the given vector of windows.
444
+ *
445
+ * The resulting merged windows is stored in the given windows object.
446
+ */
447
+ void merge_overlapping_windows (std::vector<SpreadingWindow>& windows);
448
+
449
+ /* *
450
+ * @brief Moves the blocks out of their bins and into their window.
451
+ *
452
+ * Only blocks in the given model group will be moved.
453
+ */
454
+ void move_blocks_into_windows (std::vector<SpreadingWindow>& non_overlapping_windows,
455
+ ModelGroupId group_id);
456
+
457
+ // ========================================================================
458
+ // Spreading blocks over windows
459
+ // ========================================================================
460
+
461
+ /* *
462
+ * @brief Spread the blocks over each of the given non-overlapping windows.
463
+ *
464
+ * The partial placement solution from the solver is used to decide which
465
+ * window partition to put a block into. The model group this window is
466
+ * spreading over can make it more efficient to make decisions.
467
+ */
468
+ void spread_over_windows (std::vector<SpreadingWindow>& non_overlapping_windows,
469
+ const PartialPlacement& p_placement,
470
+ ModelGroupId group_id);
471
+
472
+ /* *
473
+ * @brief Partition the given window into two sub-windows.
474
+ *
475
+ * We return extra information about how the window was created; for example,
476
+ * the direction of the partition (vertical / horizontal) and the position
477
+ * of the cut.
478
+ */
479
+ PartitionedWindow partition_window (SpreadingWindow& window);
480
+
481
+ /* *
482
+ * @brief Partition the blocks in the given window into the partitioned
483
+ * windows.
484
+ *
485
+ * This is kept separate from splitting the physical window region for
486
+ * cleanliness. After this point, the window will not have any atoms in
487
+ * it.
488
+ */
489
+ void partition_blocks_in_window (SpreadingWindow& window,
490
+ PartitionedWindow& partitioned_window,
491
+ ModelGroupId group_id,
492
+ const PartialPlacement& p_placement);
493
+
494
+ /* *
495
+ * @brief Move the blocks out of the given windows and put them back into
496
+ * the correct bin according to the window that contains them.
497
+ */
498
+ void move_blocks_out_of_windows (std::vector<SpreadingWindow>& finished_windows);
499
+
281
500
private:
282
501
// / @brief The density manager which manages the capacity and utilization
283
502
// / of regions of the device.
284
503
std::shared_ptr<FlatPlacementDensityManager> density_manager_;
504
+
505
+ // / @brief Grouper object which handles grouping together models which must
506
+ // / be spread together. Models are grouped based on the pack patterns
507
+ // / that they can form with each other.
508
+ ModelGrouper model_grouper_;
509
+
510
+ // / @brief The prefix sum for the capacity of the device, as given by the
511
+ // / density manager. We will need to get the capacity of 2D regions
512
+ // / of the device very often for this partial legalizer. This data
513
+ // / structure greatly improves the time complexity of this operation.
514
+ // /
515
+ // / This is populated in the constructor and not modified.
516
+ PerModelPrefixSum2D capacity_prefix_sum_;
285
517
};
0 commit comments