From 12720afe4113539ed521135c5e199437bb683d56 Mon Sep 17 00:00:00 2001 From: John Demme Date: Sat, 2 Oct 2021 17:40:40 -0700 Subject: [PATCH] [MSFT] Use a DeviceDB to seed a PlacementDB (#1922) Just checks validity of placements for now. --- include/circt-c/Dialect/MSFT.h | 5 ++- include/circt/Dialect/MSFT/DeviceDB.h | 8 +++- include/circt/Dialect/MSFT/PlacementDB.h | 7 ++++ .../Bindings/Python/dialects/msft.py | 9 +++++ lib/Bindings/Python/MSFTModule.cpp | 13 ++++--- lib/CAPI/Dialect/MSFT.cpp | 11 ++++-- lib/Dialect/MSFT/DeviceDB.cpp | 11 +++++- lib/Dialect/MSFT/PlacementDB.cpp | 39 ++++++++++++++++--- 8 files changed, 85 insertions(+), 18 deletions(-) diff --git a/include/circt-c/Dialect/MSFT.h b/include/circt-c/Dialect/MSFT.h index 3ca9b2909f..898ce8003c 100644 --- a/include/circt-c/Dialect/MSFT.h +++ b/include/circt-c/Dialect/MSFT.h @@ -38,7 +38,7 @@ typedef struct { void *ptr; } CirctMSFTDeviceDB; -CirctMSFTDeviceDB circtMSFTCreateDeviceDB(); +CirctMSFTDeviceDB circtMSFTCreateDeviceDB(MlirContext); void circtMSFTDeleteDeviceDB(CirctMSFTDeviceDB self); MlirLogicalResult circtMSFTDeviceDBAddPrimitive(CirctMSFTDeviceDB, MlirAttribute locAndPrim); @@ -60,7 +60,8 @@ typedef struct { MlirOperation op; } CirctMSFTPlacedInstance; -CirctMSFTPlacementDB circtMSFTCreatePlacementDB(MlirOperation top); +CirctMSFTPlacementDB circtMSFTCreatePlacementDB(MlirOperation top, + CirctMSFTDeviceDB seed); void circtMSFTDeletePlacementDB(CirctMSFTPlacementDB self); size_t circtMSFTPlacementDBAddDesignPlacements(CirctMSFTPlacementDB); MlirLogicalResult diff --git a/include/circt/Dialect/MSFT/DeviceDB.h b/include/circt/Dialect/MSFT/DeviceDB.h index 38c0c7af8f..a05931ccda 100644 --- a/include/circt/Dialect/MSFT/DeviceDB.h +++ b/include/circt/Dialect/MSFT/DeviceDB.h @@ -26,13 +26,17 @@ namespace msft { class DeviceDB { public: /// Create a DB treating 'top' as the root module. - DeviceDB(); + DeviceDB(MLIRContext *); /// Place a primitive at a location. LogicalResult addPrimitive(PhysLocationAttr); /// Check to see if a primitive exists. bool isValidLocation(PhysLocationAttr); + /// Iterate over all the primitive locations, executing 'callback' on each + /// one. + void foreach (function_ref callback) const; + private: using DimPrimitiveType = DenseSet; using DimNumMap = DenseMap; @@ -42,8 +46,10 @@ private: /// Get the leaf node. Abstract this out to make it easier to change the /// underlying data structure. DimPrimitiveType &getLeaf(PhysLocationAttr); + // TODO: Create read-only version of getLeaf. DimXMap placements; + MLIRContext *ctxt; }; } // namespace msft diff --git a/include/circt/Dialect/MSFT/PlacementDB.h b/include/circt/Dialect/MSFT/PlacementDB.h index 78f169f6de..ff5cdea807 100644 --- a/include/circt/Dialect/MSFT/PlacementDB.h +++ b/include/circt/Dialect/MSFT/PlacementDB.h @@ -14,6 +14,7 @@ #ifndef CIRCT_DIALECT_MSFT_PLACEMENTDB_H #define CIRCT_DIALECT_MSFT_PLACEMENTDB_H +#include "circt/Dialect/MSFT/DeviceDB.h" #include "circt/Dialect/MSFT/MSFTAttributes.h" #include "mlir/IR/Operation.h" @@ -34,6 +35,7 @@ class PlacementDB { public: /// Create a DB treating 'top' as the root module. PlacementDB(Operation *top); + PlacementDB(Operation *top, const DeviceDB &seed); // TODO: Add calls to model the device primitive locations. @@ -70,7 +72,12 @@ private: using DimYMap = DenseMap; using DimXMap = DenseMap; + /// Get the leaf node. Abstract this out to make it easier to change the + /// underlying data structure. + Optional getLeaf(PhysLocationAttr); + DimXMap placements; + bool seeded; }; } // namespace msft diff --git a/integration_test/Bindings/Python/dialects/msft.py b/integration_test/Bindings/Python/dialects/msft.py index 9e0bdc99bb..a6530e288d 100644 --- a/integration_test/Bindings/Python/dialects/msft.py +++ b/integration_test/Bindings/Python/dialects/msft.py @@ -95,3 +95,12 @@ with ir.Context() as ctx, ir.Location.unknown(): assert not devdb.is_valid_location(physAttr) devdb.add_primitive(physAttr) assert devdb.is_valid_location(physAttr) + + seeded_pdb = msft.PlacementDB(top.operation, devdb) + rc = seeded_pdb.add_placement(physAttr, path, "subpath", resolved_inst) + assert rc + + bad_loc = msft.PhysLocationAttr.get(msft.M20K, x=7, y=99, num=1) + rc = seeded_pdb.add_placement(bad_loc, path, "subpath", resolved_inst) + assert not rc + # ERR: error: 'hw.instance' op Could not apply placement. Invalid location diff --git a/lib/Bindings/Python/MSFTModule.cpp b/lib/Bindings/Python/MSFTModule.cpp index be4bea96c4..373f3cf903 100644 --- a/lib/Bindings/Python/MSFTModule.cpp +++ b/lib/Bindings/Python/MSFTModule.cpp @@ -27,7 +27,7 @@ using namespace mlir::python::adaptors; class DeviceDB { public: - DeviceDB() { db = circtMSFTCreateDeviceDB(); } + DeviceDB(MlirContext ctxt) { db = circtMSFTCreateDeviceDB(ctxt); } ~DeviceDB() { circtMSFTDeleteDeviceDB(db); } bool addPrimitive(MlirAttribute locAndPrim) { return mlirLogicalResultIsSuccess( @@ -37,13 +37,15 @@ public: return circtMSFTDeviceDBIsValidLocation(db, loc); } -private: CirctMSFTDeviceDB db; }; class PlacementDB { public: - PlacementDB(MlirOperation top) { db = circtMSFTCreatePlacementDB(top); } + PlacementDB(MlirOperation top, DeviceDB *seed) { + db = circtMSFTCreatePlacementDB(top, seed ? seed->db + : CirctMSFTDeviceDB{nullptr}); + } ~PlacementDB() { circtMSFTDeletePlacementDB(db); } size_t addDesignPlacements() { return circtMSFTPlacementDBAddDesignPlacements(db); @@ -162,7 +164,7 @@ void circt::python::populateDialectMSFTSubmodule(py::module &m) { }); py::class_(m, "DeviceDB") - .def(py::init<>()) + .def(py::init(), py::arg("ctxt") = py::none()) .def("add_primitive", &DeviceDB::addPrimitive, "Inform the DB about a new placement.", py::arg("loc_and_prim")) .def("is_valid_location", &DeviceDB::isValidLocation, @@ -170,7 +172,8 @@ void circt::python::populateDialectMSFTSubmodule(py::module &m) { py::arg("loc")); py::class_(m, "PlacementDB") - .def(py::init(), py::arg("top")) + .def(py::init(), py::arg("top"), + py::arg("seed") = nullptr) .def("add_design_placements", &PlacementDB::addDesignPlacements, "Add the placements already present in the design.") .def("add_placement", &PlacementDB::addPlacement, diff --git a/lib/CAPI/Dialect/MSFT.cpp b/lib/CAPI/Dialect/MSFT.cpp index cbea799775..8aacf4a27c 100644 --- a/lib/CAPI/Dialect/MSFT.cpp +++ b/lib/CAPI/Dialect/MSFT.cpp @@ -40,7 +40,9 @@ MlirLogicalResult mlirMSFTExportTcl(MlirOperation module, DEFINE_C_API_PTR_METHODS(CirctMSFTDeviceDB, circt::msft::DeviceDB) -CirctMSFTDeviceDB circtMSFTCreateDeviceDB() { return wrap(new DeviceDB()); } +CirctMSFTDeviceDB circtMSFTCreateDeviceDB(MlirContext ctxt) { + return wrap(new DeviceDB(unwrap(ctxt))); +} void circtMSFTDeleteDeviceDB(CirctMSFTDeviceDB self) { delete unwrap(self); } MlirLogicalResult circtMSFTDeviceDBAddPrimitive(CirctMSFTDeviceDB self, MlirAttribute cLoc) { @@ -59,8 +61,11 @@ bool circtMSFTDeviceDBIsValidLocation(CirctMSFTDeviceDB self, DEFINE_C_API_PTR_METHODS(CirctMSFTPlacementDB, circt::msft::PlacementDB) -CirctMSFTPlacementDB circtMSFTCreatePlacementDB(MlirOperation top) { - return wrap(new PlacementDB(unwrap(top))); +CirctMSFTPlacementDB circtMSFTCreatePlacementDB(MlirOperation top, + CirctMSFTDeviceDB seed) { + if (seed.ptr == nullptr) + return wrap(new PlacementDB(unwrap(top))); + return wrap(new PlacementDB(unwrap(top), *unwrap(seed))); } void circtMSFTDeletePlacementDB(CirctMSFTPlacementDB self) { delete unwrap(self); diff --git a/lib/Dialect/MSFT/DeviceDB.cpp b/lib/Dialect/MSFT/DeviceDB.cpp index bdbb77370f..42fa6a08eb 100644 --- a/lib/Dialect/MSFT/DeviceDB.cpp +++ b/lib/Dialect/MSFT/DeviceDB.cpp @@ -20,7 +20,7 @@ using namespace msft; // not an immediate goal. //===----------------------------------------------------------------------===// -DeviceDB::DeviceDB() {} +DeviceDB::DeviceDB(MLIRContext *ctxt) : ctxt(ctxt) {} /// Assign an instance to a primitive. Return false if another instance is /// already placed at that location. @@ -44,3 +44,12 @@ bool DeviceDB::isValidLocation(PhysLocationAttr loc) { DeviceDB::DimPrimitiveType &DeviceDB::getLeaf(PhysLocationAttr loc) { return placements[loc.getX()][loc.getY()][loc.getNum()]; } + +void DeviceDB::foreach (function_ref callback) const { + for (auto x : placements) + for (auto y : x.second) + for (auto n : y.second) + for (auto p : n.second) + callback(PhysLocationAttr::get(ctxt, PrimitiveTypeAttr::get(ctxt, p), + x.first, y.first, n.first)); +} diff --git a/lib/Dialect/MSFT/PlacementDB.cpp b/lib/Dialect/MSFT/PlacementDB.cpp index c8d0d26cb1..633979a4db 100644 --- a/lib/Dialect/MSFT/PlacementDB.cpp +++ b/lib/Dialect/MSFT/PlacementDB.cpp @@ -20,18 +20,28 @@ using namespace msft; // not an immediate goal. //===----------------------------------------------------------------------===// -PlacementDB::PlacementDB(Operation *top) : ctxt(top->getContext()), top(top) {} +PlacementDB::PlacementDB(Operation *top) + : ctxt(top->getContext()), top(top), seeded(false) {} +PlacementDB::PlacementDB(Operation *top, const DeviceDB &seed) + : ctxt(top->getContext()), top(top), seeded(false) { + + seed.foreach ([this](PhysLocationAttr loc) { (void)addPlacement(loc, {}); }); + seeded = true; +} /// Assign an instance to a primitive. Return false if another instance is /// already placed at that location. LogicalResult PlacementDB::addPlacement(PhysLocationAttr loc, PlacedInstance inst) { - PlacedInstance &cell = placements[loc.getX()][loc.getY()][loc.getNum()] - [loc.getPrimitiveType().getValue()]; - if (cell.op != nullptr) + + Optional leaf = getLeaf(loc); + if (!leaf) + return inst.op->emitOpError("Could not apply placement. Invalid location"); + PlacedInstance *cell = *leaf; + if (cell->op != nullptr) return inst.op->emitOpError("Could not apply placement ") - << loc << ". Position already occupied by " << cell.op << "."; - cell = inst; + << loc << ". Position already occupied by " << cell->op << "."; + *cell = inst; return success(); } @@ -102,6 +112,23 @@ PlacementDB::getInstanceAt(PhysLocationAttr loc) { return instF->getSecond(); } +Optional +PlacementDB::getLeaf(PhysLocationAttr loc) { + PrimitiveType primType = loc.getPrimitiveType().getValue(); + + DimNumMap &nums = placements[loc.getX()][loc.getY()]; + if (!seeded) + return &nums[loc.getNum()][primType]; + + auto primitivesF = nums.find(loc.getNum()); + if (primitivesF == nums.end()) + return {}; + auto primitives = primitivesF->second; + if (primitives.count(primType) == 0) + return {}; + return &primitives[primType]; +} + /// Walker for placements. void PlacementDB::walkPlacements( function_ref callback) {