Skip to content

Created draft of new constraints class header file #1535

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

Merged
merged 13 commits into from
Oct 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions libs/libvtrutil/src/vtr_geometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ class Rect {
template<class T>
Rect<T> bounding_box(const Rect<T>& lhs, const Rect<T>& rhs);

//Return the intersection of two given rectangles
template<class T>
Rect<T> intersection(const Rect<T>& lhs, const Rect<T>& rhs);

//Sample on a uniformly spaced grid within a rectangle
// sample(vtr::Rect(l, h), 0, 0, M) == l
// sample(vtr::Rect(l, h), M, M, M) == h
Expand Down
7 changes: 7 additions & 0 deletions libs/libvtrutil/src/vtr_geometry.tpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,13 @@ Rect<T> bounding_box(const Rect<T>& lhs, const Rect<T>& rhs) {
std::max(lhs.ymax(), rhs.ymax()));
}

template<class T>
Rect<T> intersection(const Rect<T>& lhs, const Rect<T>& rhs) {
return Rect<T>(std::max(lhs.xmin(), rhs.xmin()),
std::max(lhs.ymin(), rhs.ymin()),
std::min(lhs.xmax(), rhs.xmax()),
std::min(lhs.ymax(), rhs.ymax()));
}
//Only defined for integral types
template<typename T, typename std::enable_if<std::is_integral<T>::value>::type...>
Point<T> sample(const vtr::Rect<T>& r, T x, T y, T d) {
Expand Down
19 changes: 19 additions & 0 deletions vpr/src/base/partition.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "partition.h"
#include <algorithm>
#include <vector>

const std::string Partition::get_name() {
return name;
}

void Partition::set_name(std::string _part_name) {
name = _part_name;
}

const PartitionRegion Partition::get_part_region() {
return part_region;
}

void Partition::set_part_region(PartitionRegion pr) {
part_region = pr;
}
47 changes: 47 additions & 0 deletions vpr/src/base/partition.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#ifndef PARTITION_H
#define PARTITION_H

#include "vtr_strong_id.h"
#include "region.h"
#include "atom_netlist_fwd.h"
#include "partition_region.h"
/**
* @file
* @brief This file defines the data for a partition: a grouping of atoms that are constrained to a portion of an FPGA.
*
* A partition defines the atoms that are assigned to it, and the locations in which they can be placed.
* The locations are a union of rectangles in x, y, sub_tile space.
* Common cases include a single rectangle or a single x, y, sub_tile (specific location). More complex partitions
* with L, T or other shapes can be created with a union of multiple rectangles.
*/

/// @brief Type tag for PartitionId
struct partition_id_tag;

/// @brief A unique identifier for a partition
typedef vtr::StrongId<partition_id_tag> PartitionId;

class Partition {
public:
const std::string get_name();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put a brief comment for doxygen on top of these functions too.


void set_name(std::string _part_name);

/**
* @brief Set the PartitionRegion (union of rectangular regions) for this partition
*
* @param pr The PartitionRegion belonging to the partition
*/
void set_part_region(PartitionRegion pr);

/**
* @brief Get the PartitionRegion (union of rectangular regions) for this partition
*/
const PartitionRegion get_part_region();

private:
std::string name; ///< name of the partition, name will be unique across partitions
PartitionRegion part_region; ///< the union of regions that the partition can be placed in
};

#endif /* PARTITION_H */
31 changes: 31 additions & 0 deletions vpr/src/base/partition_region.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "partition_region.h"

PartitionRegion PartitionRegion::get_intersection(PartitionRegion part_region) {
/**for N regions in part_region and M in the calling object you can get anywhere from
* 0 to M*N regions in the resulting vector. Only intersection regions with non-zero area rectangles and
* equivalent subtiles are put in the resulting vector
* Rectangles are not merged even if it would be possible
*/
PartitionRegion pr;
Region intersect_region;
bool regions_intersect;
for (unsigned int i = 0; i < partition_region.size(); i++) {
for (unsigned int j = 0; j < part_region.partition_region.size(); j++) {
regions_intersect = partition_region[i].do_regions_intersect(part_region.partition_region[j]);
if (regions_intersect) {
intersect_region = partition_region[i].regions_intersection(part_region.partition_region[j]);
pr.partition_region.push_back(intersect_region);
}
}
}

return pr;
}

void PartitionRegion::add_to_part_region(Region region) {
partition_region.push_back(region);
}

std::vector<Region> PartitionRegion::get_partition_region() {
return partition_region;
}
38 changes: 38 additions & 0 deletions vpr/src/base/partition_region.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#ifndef PARTITION_REGIONS_H
#define PARTITION_REGIONS_H

#include "region.h"
#include "atom_netlist_fwd.h"

/**
* @file
* @brief This file defines the PartitionRegions class. The PartitionRegions class is used to store the union
* of regions that a partition can be placed in.
*/

class PartitionRegion {
public:
/**
* @brief Return the intersection of two PartitionRegions
*
* @param part_region The PartitionRegion that the calling object will be intersected with
*/
PartitionRegion get_intersection(PartitionRegion part_region);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets follow Keith's suggestion and be more like Rect.
Move this to the bottom of the header file (outside the class), and make it
PartitionRegion insersection (PartitionRegion a, PartitionRegion b);


/**
* @brief Add a region to the union of regions belonging to the partition
*
* @param region The region to be added to the calling object
*/
void add_to_part_region(Region region);

/**
* @brief Return the union of regions
*/
std::vector<Region> get_partition_region();

private:
std::vector<Region> partition_region; ///< union of rectangular regions that a partition can be placed in
};

#endif /* PARTITION_REGIONS_H */
81 changes: 81 additions & 0 deletions vpr/src/base/region.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "region.h"

/// @brief sentinel value for indicating that a subtile has not been specified
constexpr int NO_SUBTILE = -1;

Region::Region() {
sub_tile = NO_SUBTILE;

//default rect for a region is (-1, -1, -1, -1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explain why (invalid, to help catch uninitialized use).

region_bounds.set_xmin(-1);
region_bounds.set_ymin(-1);
region_bounds.set_xmax(-1);
region_bounds.set_ymax(-1);
}

vtr::Rect<int> Region::get_region_rect() {
return region_bounds;
}

void Region::set_region_rect(int _xmin, int _ymin, int _xmax, int _ymax) {
region_bounds.set_xmin(_xmin);
region_bounds.set_xmax(_xmax);
region_bounds.set_ymin(_ymin);
region_bounds.set_ymax(_ymax);
}

int Region::get_sub_tile() {
return sub_tile;
}

void Region::set_sub_tile(int _sub_tile) {
sub_tile = _sub_tile;
}

bool Region::do_regions_intersect(Region region) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to intersect, should probably make this
bool do_regions_intersection (Region a, Region b);
and it would go outside the class, at the bottom of this header.
If it's accessing private variables, then you'll need to make it a friend function.

bool intersect = true;

vtr::Rect<int> region_rect = region.get_region_rect();
vtr::Rect<int> intersect_rect;

intersect_rect = intersection(region_bounds, region_rect);

/**
* if the intersection rectangle is empty or the subtile of the two regions does not match,
* the regions do not intersect
*/
if (intersect_rect.empty() || sub_tile != region.get_sub_tile()) {
return intersect = false;
}

return intersect;
}

Region Region::regions_intersection(Region region) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to intersection, and make it a global function at the bottom of the header file (outside class):
Region intersection (Region a, Region b);
// May have to be a friend function of class Region.

Region intersect;

/**
* If the subtiles of the two regions don't match, there is no intersection.
* If they do match, the intersection function if used to get the overlap of the two regions' rectangles.
* If there is no overlap, an empty rectangle will be returned.
*/
if (sub_tile == region.get_sub_tile()) {
intersect.set_sub_tile(sub_tile);
vtr::Rect<int> region_rect = region.get_region_rect();
vtr::Rect<int> intersect_rect;

intersect_rect = intersection(region_bounds, region_rect);

intersect.set_region_rect(intersect_rect.xmin(), intersect_rect.ymin(), intersect_rect.xmax(), intersect_rect.ymax());
}

return intersect;
}

bool Region::locked() {
return region_bounds.xmin() == region_bounds.xmax() && region_bounds.ymin() == region_bounds.ymax() && sub_tile != NO_SUBTILE;
}

bool Region::empty() {
return region_bounds.empty();
}
61 changes: 61 additions & 0 deletions vpr/src/base/region.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#ifndef REGION_H
#define REGION_H

#include <vtr_geometry.h>

/**
* @file
* @brief This file defines the Region class. The Region class stores the data for each constraint region.
*
* This includes the x and y bounds of the region rectangle and its sub_tile. To lock a block down to a specific location,
* when defining the region specify xmin = xmax, ymin = ymax, and specify a subtile value.
*
*/

class Region {
public:
Region();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add @brief on these methods too so they show up in Doxygen (then build Doxygen to the vtr docs and make sure it shows up).


vtr::Rect<int> get_region_rect();

void set_region_rect(int _xmin, int _ymin, int _xmax, int _ymax);

int get_sub_tile();

void set_sub_tile(int _sub_tile);

/**
* @brief Return whether the region is empty, based on whether the region rectangle is empty
*/
bool empty();

/**
* @brief Returns whether two regions intersect
*
* Intersection is the area of overlap between the rectangles of two regions,
* given that both regions have matching subtile values, or no subtiles assigned to them
* The overlap is inclusive of the x and y boundaries of the rectangles
*
* @param region The region to intersect with the calling object
*/
bool do_regions_intersect(Region region);

/**
* @brief Returns the coordinates of intersection of two regions
*
* @param region The region to intersect with the calling object
*/
Region regions_intersection(Region region);

/**
* @brief Checks whether a block is locked down to a specific x, y, subtile location
*/
bool locked();

private:
//may need to include zmin, zmax for future use in 3D FPGA designs
vtr::Rect<int> region_bounds; ///< xmin, ymin, xmax, ymax inclusive
int sub_tile; ///< users will optionally select a subtile
};

#endif /* REGION_H */
45 changes: 45 additions & 0 deletions vpr/src/base/vpr_constraints.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "vpr_constraints.h"

void VprConstraints::add_constrained_atom(const AtomBlockId blk_id, const PartitionId part_id) {
constrained_atoms.insert({blk_id, part_id});

auto got = constrained_atoms.find(blk_id);

if (got == constrained_atoms.end()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each atom can be in only one partition; if it's already in a partition it will be switched to the new partition instead.

constrained_atoms.insert({blk_id, part_id});
} else {
got->second = part_id;
}
}

PartitionId VprConstraints::get_atom_partition(AtomBlockId blk_id) {
PartitionId part_id;

auto got = constrained_atoms.find(blk_id);

if (got == constrained_atoms.end()) {
return part_id = PartitionId::INVALID();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Not in a partition, i.e. unconstrained.

} else {
return got->second;
}
}

void VprConstraints::add_partition(Partition part) {
partitions.push_back(part);
}

Partition VprConstraints::get_partition(PartitionId part_id) {
return partitions[part_id];
}

std::vector<AtomBlockId> VprConstraints::get_part_atoms(PartitionId part_id) {
std::vector<AtomBlockId> part_atoms;

for (auto& it : constrained_atoms) {
if (it.second == part_id) {
part_atoms.push_back(it.first);
}
}

return part_atoms;
}
Loading